
"pseudo-signatures > usage patterns"
Hello all,
Can we write down pros and cons for concepts implemented via pseudo-signatures (C++0x-like and Boost.Generic) vs. usage patterns (N3351 and Boost.Contract)?
I think such comparison looks different when you want to provide the best solution for STL and different when you want to provide the solution for *every* generic library. STL is particular in two ways: first, it has been in use for years, and any solution needs to fit seamlessly into the existing code (even if the code doesn't adhere to the best practices of generic programming); second, STL uses operators heavily. I expect no other generic library to make such extensive use of operators. I have never tried to implement support for any type of concepts, so I am only looking at the problem from end user's perspective; arguments like "pseudo-signatures make it easier to generate archetypes" do not appeal to me that much (which admittedly may be an ignorant approach). Informally, I can say that I expect of an iterator a post- and pre-increment, comparison, and dereference. With pseudo signatures I express it as: Iter& operator++(Iter); Iter operator++(Iter, int); // note the dummy int bool operator==(Iter const&, Iter const&); // bool or convertible to bool? ValueType<Iter>& operator*(Iter const&); But how do I say "convertible to bool"? With usage-patterns, I type: Iter& == { ++it }; Iter == { it++ }; bool = { it == jt }; // convertible ValueType<Iter>& == { *it }; To me, the latter notation appears more appealing: it is shorter, it gives me a concise way of specifying "has exactly this type" or "is implicitly convertible to" or "is explicitly convertible to". But this elegance may be only due to the fact that I am using operators. For other concepts that do not want operators it might have been uglier: Socket == { get_socket(env, params) }; vs. Socket get_params(Env, Params); Next, when I add two numbers with pseudo signatures I type: T operator+(Tconst&, Tconst&); vs: T == { a + b }; But does the following function: X operator+(X& a, X&b); // mutable references Satisfy the pseudo-signature requirement or not? I know it does satisfy the usage pattern, and not every programmer is (has the luxury to be) const-correct. Next, for OutputIterator, I want operation (*it = v) to be valid. But I never intend to use the assignment alone or the indirection alone. With usage-patterns, I can write: *it = v; // cannot use the result of the assignment With pseudo signatures, I need to specify at least two declarations, and I need to specify what the operator* returns, even though it should be an implementation detail: typename DerefResult; DerefResult operator*(Iter&); void operator=(DerefResult, ValueType<Iter>); But again, maybe this operation should be output(it, v), and it is STL's limitation that it uses a combination of operators for a sort-of 'atomic' operation. Regards, &rzej