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