Generality creep

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Mar 31 06:53:03 UTC 2019


On Saturday, March 30, 2019 1:38:46 PM MDT ag0aep6g via Digitalmars-d wrote:
> On 30.03.19 19:32, Jonathan M Davis wrote:
> > RefRange is trying to force reference semantics, which then
> > fundamentally
> > doesn't fit with forward ranges. It sort of half fits right now, because
> > of save, but as with forward ranges that are reference types, it causes
> > problems, and code frequently isn't going to work with it without extra
> > work.
> >
> > As such, I really don't think that RefRange makes sense fundamentally.
>
> You haven't spelled it out, but I suppose you also think that classes
> don't make sense as forward ranges. And Andrei has stated something to
> the effect that they wouldn't be supported in his redesign.
>
> That is fine for a range redesign. But with the definitions we have
> right now, classes can be forward ranges, and Phobos should work with
> them. And if Phobos works with classes, it can work with RefRange (if we
> cut out opAssign).
>
> If RefRange really is fundamentally at odds with current ranges, I'd be
> interested in an example where it causes trouble that isn't due to
> opAssign (or opSlice() which also shouldn't be there). Maybe I just fail
> to see the problem.
>
> One issue I'm aware of is that RefRange does a GC allocation on `save`.
> That isn't pretty, but I wouldn't call it fatal.
>
> I've said before that "we can cut out the bad parts" of RefRange,
> referring to opAssign, but I think I was wrong. Deprecating assignment
> would be so limiting that we might as well deprecate the whole thing.
>
> Then again, Walter has made (limited) efforts to support ranges that are
> non-assignable due to const fields. Nobody acknowledges that those exact
> changes also work to accommodate RefRange, but they do.

Fundamentally, forward ranges are essentially value types. They've just had
their copy operation moved to save in order to accommodate classes. They
have to be copyable to work (even if that copying is done via save), and any
function that requires a forward range _will_ copy it via save, or it
wouldn't require a forward range. Once the range is saved, RefRange is
pretty useless, because the results of what are done to the copy don't
affect the original.

And to use RefRange, you're basically depending on implementation details of
a particular algorithm and when it chooses to call save and what exactly it
does with the original before and after calling save - something that is not
part of the function's API or any guarantee that it makes. And because the
actual semantics of copying a range depend on how it's implemented,
algorithms can't rely on whether copying a range will result in an
independent copy or not and are free to rearrange when they do or don't copy
a range so long as they don't use the original range after it's been copied.
They're also free to change when save is called so long as the function's
result is the same. It's also assumed that the function can do whatever it
pleases with the original so long as it doesn't violate the range API, since
in general, you can't use a range again after it's been copied (because
doing so would not work the same with all range types).

RefRange on the other hand is basically trying to get access to the results
of the first part of the algorithm prior to the call save (and possibly some
of what's done to the original after the call to save). It's purposefully
setting up the code to reuse a range in circumstances where you can't reuse
a range in generic code. The code isn't necessarily generic, which does
change things, but if the algorithm you're passing RefRange too is generic,
then it wasn't written with RefRange in mind, and there will be no
expectation that the caller will do anything with the range that was passed
in. If anything, the expection is that they won't do anything with it except
maybe assign the result of the function to it to reuse the variable.

Basically, RefRange is trying to fight how forward ranges work, and while
that works in corner cases, in general, it's a mess. And the odds of code
that uses RefRange breaking due to changes to algorithms that would
otherwise be fine are pretty high, because code using RefRange is depending
on the implementation details of any functions that RefRange is passed to.

So, while RefRange might be okay in code that's written specifically for use
with RefRange, in general, it's a terrible idea. And I really regret that I
got into Phobos. The fact that I did just shows how much less I understood
about ranges at the time.

- Jonathan M Davis





More information about the Digitalmars-d mailing list