Indiana Unversity logo[ConceptGCC]

ConceptGCC :

Re: Self referential concepts and infinite loops in conceptg++

From: Doug Gregor (dgregor_at_[hidden])
Date: 2007-03-21 10:28:55


Hello Tom,

On Mar 18, 2007, at 12:25 AM, tom.honermann_at_[hidden] wrote:
> I've been playing with Alpha 5 of ConceptGCC on RedHat Linux EL4 in
> order to validate a design for polytypic containers and iterators
> (ie, a container that holds objects of different types with
> iterator classes for iterating through the polytypic members).

Interesting!

> The PolytypicSequenceIterator concept specifies an 'operator++'
> which returns another type that models PolytypicSequenceIterator,
> or a type modelling PolyTypicSequenceIteratorEnd representing the
> end of the sequence. This is resulting in two issues:
> 1: Need for an || constraint - which ConceptGCC doesn't currently
> support (and may never considering current thinking on support of
> this feature)

|| constraints have been removed from the latest concepts proposal,
because nobody has any idea how to implement them in a way that isn't
very poor.

> 2: Having a concept specify a member type that models the same
> concept is causing 'conceptg++' to go into an infinite loop (see
> below).

Ah, yes. I know exactly where this infinite loop comes from. Fixing
it has spawned a very interesting discussion among several of the
authors of concepts, because recursive constraints like these are
rather non-trivial.

> I was hoping I might be able to use 'late_check' to work around
> this, but either support for 'late_check' in ConceptGCC is not
> complete, or my understanding of 'late_check' is incomplete.
> Additionally, it sounds like the design of 'late_check' is up for
> re-consideration.

Yes, late_check has been redesigned, and ConceptGCC's support for it
is incomplete (at best).

> Consider the following code:
>
> #include <concepts>
>
> concept PolytypicSequenceIteratorEnd<typename T> {
> };
>
> concept PolytypicSequenceIterator<typename T> {
> typename next_iterator = T::next_iterator;
> where PolytypicSequenceIterator<next_iterator> ||
> PolytypicSequenceIteratorEnd<next_iterator>;
>
> next_iterator operator++(const T&);
> };
>
> concept PolytypicSequence<typename T> {
> PolytypicSequenceIterator iterator;
> PolytypicSequenceIteratorEnd iterator_end;
>
> iterator T::begin();
> iterator_end T::end();
> };

Very neat. We'd like this to work, but as I said we're trying to
figure out just how recursive constraints can work. Now, assuming
that we'll find a way to make recursive constraints work, let's take
a look at refactoring this to avoid the `||' constraint, because it's
unlikely those will come back.

The key is to think of requirements not in terms of "I'll either get
an A or a B back", but to say, "I'll get something that is an X, and
might also be a Y". In the above example, a
PolytypicSequenceIteratorEnd is an iterator, but it may or may not be
incrementable with ++. The key is that we want to express common
functionality, then variations on that common functionality. So, we
could write the concepts like this:

   concept PolytypicIterator<typename T> {
   }

   concept IncrementablePolytypicIterator<typename T> :
PolytypicIterator<T> {
     typename next_iterator = T::next_iterator;
     where PolytypicIterator<next_iterator>;

     next_iterator operator++(const T&);
   }

   concept PolytypicSequence<typename T> {
         PolytypicIterator iterator;
         PolytypicIterator iterator_end;

         iterator T::begin();
         iterator_end T::end();
   }

In writing the PolytypicSequence concept, I also fixed a minor bug...
the prior PolytypicSequence required that "iterator" be incrementable
(i.e., it could not be a PolytypicSequenceIteratorEnd), so it would
not be possible to have a zero-length polytypic sequence. By stating
only that iterator and iterator_end are PolytypicIterators, we allow
empty and non-empty sequences.

How do we use these concepts? Actually, your visitor function works
fine with just a minor change in concept names:

   template<PolytypicSequence sequence>
   void PolytypicSequenceVisitor(sequence s) {
           PolytypicSequenceVisitor(s.begin());
   }

   template<IncrementablePolytypicIterator iterator>
   void PolytypicSequenceVisitor(iterator i) {
           PolytypicSequenceVisitor(++i);
   }

   template<PolytypicIterator iterator_end>
   void PolytypicSequenceVisitor(iterator_end i) {
   }

        Cheers,
        Doug