range behaviour

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Tue May 13 10:30:47 PDT 2014


On Tue, May 13, 2014 at 09:58:09AM -0700, Jonathan M Davis via Digitalmars-d wrote:
> On Tue, 13 May 2014 18:38:44 +0200
> Benjamin Thaut via Digitalmars-d <digitalmars-d at puremagic.com> wrote:
> 
> > I know that there was a recent discussion about how the methods of
> > ranges should behave.
> >
> > E.g.
> >
> > - Does empty always have to be called before calling front or
> > popFront?
> 
> Certainly, ranges are pretty much always used this way, but there was
> some debate as to whether empty could have work done in it (and thus
> _had_ to be called). However, I believe that the consensus was that
> yes, empty had to be called (certainly, both Walter and Andrei felt
> that way).
> 
> > - Is it allowed to call front multiple times between two calls to
> > popFront?
> 
> Definitely. _Lots_ of range-based code would break otherwise - though
> there are casese where that can cause problems depending on what you
> rely on (e.g.  map!(a => to!string(a)) will return equal strings, but
> they aren't the _same_ string).
> 
> > Was there a result of that discussion? Is it documented somewhere?
> 
> AFAIK, there's just the semi-recent newsgroup discussion on the
> matter, though maybe someone put something up on the wiki.
[...]

I second all of the above.

In generic code (all range-based code is generic, since otherwise
there's no point in using the range abstraction, you should just use the
concrete type directly), you cannot assume anything about what .empty,
.front, and .popFront() might do apart from what is specified in the
range API.

Therefore, since .front and .popFront have unspecified behaviour if
.empty is false, the only correct way to write range-based code is to
call .empty first to determine whether it's OK to call .front and
.popFront.

Furthermore, it doesn't make sense to restrict .front to be called only
once, since otherwise we should simplify the API by merging .front and
.popFront and have the same function both return the current element and
advance to the next element. The fact that they were designed to be
separate calls implies that .front can be called multiple times.

Of course, for efficiency purposes range-based code (esp. Phobos code)
should try their best to only call .front once. But it should be
perfectly permissible to call .front multiple times.

Lastly, since the range API is an *abstraction*, it should not dictate
any concrete implementation details such as whether .empty can do
non-trivial initialization work. Properly-written range-based code
should be able to handle all possible implementations of the range API,
including those that do non-trivial work in .empty.

Of course, that doesn't mean it's a *good* idea for .empty to do
non-trivial work. The code is probably cleaner if that work is done
somewhere else (like in the ctor or the function that returns the
range). But that's an issue for the implementer of the range, not the
consumers. The consumers of the range should not depend on one behaviour
or the other, so that they will still work correctly when given a range
that, for whatever reason, needs to do non-trivial work in .empty.


T

-- 
Prosperity breeds contempt, and poverty breeds consent. -- Suck.com


More information about the Digitalmars-d mailing list