Boost logo

Boost :

Subject: Re: [boost] Provisional Boost.Generic and Boost.Auto_Function (concepts without concepts)
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2010-12-15 21:29:27


On Wed, Dec 15, 2010 at 2:23 PM, Matt Calabrese <rivorus_at_[hidden]> wrote:

> Alright, I'm updating the way concept maps are defined and I'd like some
> feedback here before I go through the task of creating yet another
> named-parameter macro. In designing Generic, I've gone in a slightly
> different direction from what would have been C++0x concepts and concept
> maps. In particular, instead of having "auto concepts", all concepts are by
> default explicit, however, a programmer can create one or more "auto concept
> maps" for a given concept. These "auto concept maps" act as concept maps
> with optional conditions (SFINAE and metafunction conditions).
>

Bump hoping that someone has feedback, positive or negative, about this
approach.

Also, for a while now I've been thinking about a future addition to the
library that's way far off, but I'd like to hear people's opinion on it now,
or at least have people thinking about it for the long while before I ever
get to possibly implementing it.

The idea is const-qualification for concepts, which I'll try to briefly
explain. First, the motivating use-case is the "circle-ellipse" problem (
http://en.wikipedia.org/wiki/Circle-ellipse_problem ).

I'm sure people are familiar with it already, but in short, a circle is a
kind of ellipse, however, if an ellipse concept requires mutating operations
for individual axes, then a circle can't really be considered a refinement
of ellipse. Instead, the ideal solution is likely to have an Ellipse concept
that doesn't have any mutating operations, and a MutableEllipse that is a
refinement of Ellipse but that has mutating operations. A Circle can then be
considered a refinement of Ellipse without a problem. My idea is to
eventually directly support this idea via a form of const-qualification for
concepts. Take the following example, in pseudo-code:

//////////
concept Ellipse< T >
  : Regular< T >
{
const: // used to specify that the following are required even for const
Ellipse
  typename value_type;
  value_type axis_0( T const& );
  value_type axis_1( T const& );
mutable: // The following are only required for non-const Ellipse
  void axis_0( T&, value_type ); // set the axis length
  void axis_1( T&, value_type ); // set the axis length
}

// The above code effectively creates 2 concepts:
// a "const Ellipse" concept that can view properties of the ellipse
// an "Ellipse" concept that refines "const Ellipse" and that adds
mutators

// Now, the implementation of the Circle concept:
concept Circle< T >
  : const Ellipse< T > // A circle meets the requirements of const Ellipse
  , Regular< T > // And it's also a non-const Regular type
{
const:
  value_type radius( T const& );
mutable:
  void radius( T&, value_type );
}
//////////

There are some subtleties, but I think the above code should hopefully make
some sense simply from reading it. The overall idea is that a Circle meets
the requirements of const Ellipse and is also a Regular type. This should be
a concise way to represent that relationship.

To be a little more clear, here is what I'd imagine the above code would
effectively generate:

//////////
concept ConstEllipse< T >
  : ConstRegular< T >
{
  typename value_type;
  value_type axis_0( T const& );
  value_type axis_1( T const& );
}

concept Ellipse< T >
  : ConstEllipse< T >
  , Regular< T >
{
  void axis_0( T&, value_type ); // set the axis length
  void axis_1( T&, value_type ); // set the axis length
}

concept ConstCircle< T >
  : ConstEllipse< T >
  , ConstRegular< T >
{
  value_type radius( T const& );
}

concept Circle< T >
  : ConstCircle< T >
  , Regular< T >
{
  void radius( T&, value_type );
}
//////////

Notice that ConstEllipse refines ConstRegular, whereas Ellipse refines both
ConstEllipse and Regular. In other words, the "constness" of a
concept propagates to the concepts that it refines. I haven't shown the
implementation of Regular, but it would be what you'd expect from such a
concept, but with, I.E. assignment specified as mutable, similar to the
mutable specifications for Ellipse. Specifically, this means that a const
Regular< T > wouldn't require assignment, which is why Circle has to
explicitly refine Regular< T >.

In the end, I think this should be a concise way to handle situations
equivalent to the circle-ellipse problem without programmers having to
manually create separate mutable and immutable concepts. Have I made this
point clear?

If anyone has anything to say about this idea please let me know, especially
anything negative. Again, if I ever pursue this idea at all, it won't be for
a very long time anyway, but I'd like people to think about it now.

-- 
-Matt Calabrese

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk