OT: for (;;) {} vs while (true) {}

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Fri Nov 25 08:47:25 PST 2016


On Friday, November 25, 2016 10:46:15 Steven Schveighoffer via Digitalmars-d 
wrote:
> On 11/25/16 8:24 AM, Jonathan M Davis via Digitalmars-d wrote:
> > On Friday, November 25, 2016 07:59:07 Andrei Alexandrescu via
> > Digitalmars-d>
> > wrote:
> >> On 11/25/2016 07:53 AM, Dennis Ritchie wrote:
> >>> https://github.com/dlang/phobos/blob/master/std/algorithm/comparison.d
> >>> #L
> >>> 591
> >>
> >> I like that function. If I were to review it now, I'd approve with
> >> these
> >> nits:
> >>
> >> * drop the parens for popFront
> >
> > I would point out that technically, that breaks the range API.
> > isInputRange requires that popFront be callable with parens, but it
> > does not require that it be callable without parens. So, someone could
> > define popFront as a public member variable with an overloaded opCall.
> > That would not compile if it were used with code that called popFront
> > without parens even though it would compile with isInputRange.
>
> This is a misunderstanding. The missing parens is for *usage* of the
> range, not *definition* of the range. It won't affect isInputRange at all.

It's not a misunderstanding.

template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = R.init;     // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront();     // can invoke popFront()
        auto h = r.front; // can get the front of the range
    }));
}

calls popFront with parens. That means that it's perfectly legal per
isInputRange to define popFront such that it's a callable that does _not_
work with optional parens. So, if it were a member variable that defined
opCall or was a delegate, then to use it, the parens are required. That
means that I could define a range that passes isInputRange but does not work
with code that called popFront without parens. As isInputRange is currently
defined, it's perfectly legal.

> This case you have of defining a popFront member variable with opCall --
> don't do that, it will break things (I'm sure there are already many
> places where popFront is called without parens). I don't think that's a
> case that we need worry about.

It's a case that's currently legal. It's just not one that's particularly
likely.  We can certainly change isInputRange to make such a case illegal.
But as it stands, someone could have defined such a range, and it would work
with a _lot_ range-based code, because it's very common to call popFront
with parens, and if such a range were being used with a function in Phobos,
and that function were changed to call popFront without parens, it would
break code.

So, if we want to change the definition of isInputRange to get rid of this
problem, fine. I'm just pointing out that as isInputRange is currently
defined, calling popFront without parens would result in that code not
working with ranges that are perfectly legal per isInputRange and could be
perfectly legitimate ranges in all aspects of how they function.

And calling empty _with_ parens even though it would be legal in most cases
right now would have the exact same problem except in reverse. Everything
wasn't a callable wouldn't work - including stuff like empty on infinite
ranges.

D allows us to be lax with syntax to some extent, but we need to be careful
with how we deal with that in generic code, or we're going to end up with
stuff that should work but doesn't just because parens happened to have been
used or not in a particular piece of code.

- Jonathan M Davis



More information about the Digitalmars-d mailing list