output ranges: by ref or by value?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Jan 2 10:51:48 PST 2010


Steven Schveighoffer wrote:
> On Sat, 02 Jan 2010 13:06:25 -0500, Andrei Alexandrescu 
> <SeeWebsiteForEmail at erdani.org> wrote:
> 
>> Steven Schveighoffer wrote:
>>> On Fri, 01 Jan 2010 18:45:35 -0500, Andrei Alexandrescu 
>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>
>>>> Rainer Deyke wrote:
>>>>> Andrei Alexandrescu wrote:
>>>>>> If the implementor of consume() forgets to call save(), the 
>>>>>> situation is
>>>>>> unpleasant albeit not catastrophic: for most struct ranges things 
>>>>>> will
>>>>>> continue to work, but for class ranges the function will fail to 
>>>>>> perform
>>>>>> to spec. I don't know how to improve on that.
>>>>>  Require that all ranges are structs.  If you want to implement a 
>>>>> range
>>>>> as a class, use a wrapper struct that creates a new object in its
>>>>> postblit function.  The wrapper struct can be made generic and 
>>>>> placed in
>>>>> the standard library.
>>>>>  Same performance as the current approach, slightly more effort on the
>>>>> part of the range implementor, much easier and less error-prone on the
>>>>> side of the range user.
>>>>
>>>> Oh, besides it doesn't work for struct ranges that iterate one-pass 
>>>> streams.
>>>  What does save do in those cases?
>>>  -Steve
>>
>> It provides a syntactic differentiation between input ranges and 
>> forward ranges.
>>
>> STL's input iterators are syntactically indistinguishable from forward 
>> iterators. Because of that, all STL algorithms that expect forward 
>> ranges will also compile and run with input ranges, although never 
>> with the expected result. This has been a lingering problem with 
>> C++98, and a key motivator for concepts. Since syntactic differences 
>> cannot be used to distinguish between input and forward iterators, the 
>> reasoning went, we need something else as a discriminator - and that 
>> would be a concept: someone who defines an input iterator declares it 
>> obeys the input iterator concept, whereas someone defining a forward 
>> iterator declares it obeys the forward iterator concept.
>>
>> During the meltdown of concepts, a number of people including Bjarne 
>> Stroustrup and myself have suggested that a simple workable solution 
>> would be to define an extra function a la "save" that is used in 
>> algorithms and only supported by forward iterators, but not by input 
>> iterators. Then, algorithms use save() and will correctly refuse to 
>> compile calls with input iterators. The remaining risk is that someone 
>> writes an algorithm and forgets to use save().
> 
> Would it not be as useful then to just define attributes on the type and 
> save a bunch of useless/weird looking code?
> 
> that is, have an enum value inside the type that defines its state can 
> be saved.  It seems to me like save is the equivalent of that anyways, 
> since its possible to forget to use it, and still have your code compile.

If you have an enum that says a range's state can be saved, then you 
still need a function to effect that save :o). So you added, not 
removed, bloat.

> Basically, it appears to me that save either a) doesn't compile or b) is 
> the equivalent of assignment.  It doesn't seem to add much to the 
> functionality.

No, for class ranges save() is nontrivial (a sort of clone). I suspect 
even struct ranges for certain file-oriented stuff would do nontrivial 
work (e.g. open the file anew and fseek() on the current position etc.)

> This is all except for classes, which I think have no business being 
> ranges in the first place.

Well then how would the container hierarchy work? It does need range 
interfaces. How does dcollections deal with that?


Andrei



More information about the Digitalmars-d mailing list