range.save

Andrei Alexandrescu via Digitalmars-d digitalmars-d at puremagic.com
Thu Nov 26 09:23:07 PST 2015


On 11/20/2015 11:34 AM, Sönke Ludwig wrote:
> Am 20.11.2015 um 16:37 schrieb Andrei Alexandrescu:
>> On 11/20/2015 04:42 AM, Sönke Ludwig wrote:
>>> I think that .save is a serious design flaw in the range API
>>
>> How would you redo it? -- Andrei
>
> That's why I wrote that the alternatives had their own issues - I
> unfortunately don't have a solution to this either. Making usage errors
> fail loudly at runtime is the only one improvement I had in mind that
> wouldn't result in unacceptable code breakage.
>
> Now if we could exclude reference type ranges from the picture* and
> ignore the fact that this would break tons of code, I think making input
> ranges non-copyable and using the postblit constructor to do the job of
> save() would be the right approach.

(had this in my other's laptop outbox for a while)

The baseline was STL's input iterators, which were quite bad - there's 
no syntactic distinction between input and forward iterators, which 
makes the entire matter a convention. That's not the case for any other 
iterators - code using their capabilities won't compile with weaker 
iterators (nice).

So initially I thought a simple solution would be this:

struct MyForwardRange
{
     enum bool isForward = true;
     ... empty, front, popFront ...
}

enum isForwardRange(R) =
   is(typeof(R.isForward)) && R.isForward;

Then there's no need for .save(), and isForward!R can be used for 
constraints etc. Reference forward ranges are not supported but then 
that's liberating (fewer complications), rare, and easy to work around 
by wrapping.

Looking back, the only reason for which I didn't go that way was fear; I 
simply hadn't seen such an idiom and I was afraid it'd be too 
nonconformist. Introspection was new and back then quite arcane, and the 
idioms were unclear. So I went with a more conventional solution of 
adding one method.

Today that's the way I'd do it, and in fact it is the way the new 
collections will work exactly that way - if a type exposes 
isStdCollection then it commits to implementing the collection 
primitives as specified.

As of right now the situation with ranges is suboptimal - you need to 
use .save() but if you don't the sheer copy works most of the time, just 
not always. It may be nice to improve on that a bit, for example to 
require input ranges that are not forward ranges to indeed have 
reference semantics. Or require forward ranges to define .save() but 
only with the body { return this; }. Either of these would break code.


Andrei



More information about the Digitalmars-d mailing list