Boost logo

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