|
Boost : |
Subject: Re: [boost] [contract] concepts: pseudo-signatures vs. usage patterns
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2012-10-11 09:07:56
>
> >
> > "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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk