| Thread overview | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 30, 2009 forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
If we want to allow people to create ranges that are classes (as opposed to structs) the requirement for a save() function is a must. This is because copying class ranges with
Range copy = original;
only creates a new alias for original; the two share the same state.
So this solves our forward vs. input ranges dilemma quite nicely: the save() function at the same time allows distinction between the two (input ranges don't define a save() function) and also allows ranges to be implemented as classes as well as structs.
To summarize:
Input ranges: empty front popFront
Forward ranges: + save
Bidir ranges: + back popBack
Random-access ranges: + opIndex opIndexAssign
The disadvantage is that all non-input ranges must define save(), which is a trivial functions in most cases:
Range save() { return this; }
Andrei
| ||||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu:
> If we want to allow people to create ranges that are classes (as opposed
> to structs) the requirement for a save() function is a must. This is
> because copying class ranges with
> Range copy = original;
> only creates a new alias for original; the two share the same state.
Do you mean a function to be called with the "dup" attribute?
Maybe such method can be called dup()?
Bye,
bearophile
| |||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote: > If we want to allow people to create ranges that are classes (as opposed > to structs) the requirement for a save() function is a must. This is > because copying class ranges with > > Range copy = original; > > only creates a new alias for original; the two share the same state. Allowing ranges to have either value or reference semantics is a disaster, because it turns two very common and very obvious operations (assignment and argument passing) into implementation-defined behavior. I prefer value semantics over reference semantics, but using either one consistently would be infinitely preferable over leaving the choice to the implementor. -- Rainer Deyke - rainerd@eldwood.com | |||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> If we want to allow people to create ranges that are classes (as opposed
> to structs) the requirement for a save() function is a must. This is
> because copying class ranges with
>
> Range copy = original;
>
> only creates a new alias for original; the two share the same state.
>
> So this solves our forward vs. input ranges dilemma quite nicely: the
> save() function at the same time allows distinction between the two
> (input ranges don't define a save() function) and also allows ranges to
> be implemented as classes as well as structs.
>
> To summarize:
>
> Input ranges: empty front popFront
>
> Forward ranges: + save
>
> Bidir ranges: + back popBack
>
> Random-access ranges: + opIndex opIndexAssign
>
> The disadvantage is that all non-input ranges must define save(), which is a trivial functions in most cases:
>
> Range save() { return this; }
>
>
>
> Andrei
What about passing of ranges into functions? Does this mean that all algorithms must call save at the start of the algorithm? Or will callers of functions have to do defensive saves to avoid changes to their range? Maybe all ranges be passed as ref arguments now?
I don't think the answer is as simple as just having a save function.
| |||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote:
> Andrei Alexandrescu:
>> If we want to allow people to create ranges that are classes (as opposed to structs) the requirement for a save() function is a must. This is because copying class ranges with
>> Range copy = original;
>> only creates a new alias for original; the two share the same state.
>
> Do you mean a function to be called with the "dup" attribute?
> Maybe such method can be called dup()?
Except as I understand it save() is only supposed to save the iteration state, not duplicate the elements being iterated over. So it has different semantics that dup. For arrays, the definition would be something like this:
T[] save(T)(T[] arr) { return arr; }
(presumably implemented in std.range or something)
| |||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Rainer Deyke | Rainer Deyke:
> Allowing ranges to have either value or reference semantics is a disaster,
At the moment you can put the methods that define a range into a struct, or inside an class (just like you can put opApply inside a struct or class). What do you suggest? To allow such methods inside classes only? Uhm.
Bye,
bearophile
| |||
May 30, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote: > Rainer Deyke: >> Allowing ranges to have either value or reference semantics is a disaster, > > At the moment you can put the methods that define a range into a struct, or inside an class (just like you can put opApply inside a struct or class). What do you suggest? To allow such methods inside classes only? Uhm. Ranges are defined as a concept. A concept is not just a list of methods, but a specification for the semantics of the type. I suggest that the "range" concept unambiguously defines the semantics of the assignment operations. My preference is to use value semantics. Move semantics would also work. Both would require a 'struct' type (which can be a thin wrapper around a 'class' type). (My real preference is to remove the value/reference type schism entirely, but that's not what I'm suggesting here.) -- Rainer Deyke - rainerd@eldwood.com | |||
June 01, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sat, 30 May 2009 13:18:06 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > If we want to allow people to create ranges that are classes (as opposed to structs) the requirement for a save() function is a must. This is because copying class ranges with > > Range copy = original; > > only creates a new alias for original; the two share the same state. > > So this solves our forward vs. input ranges dilemma quite nicely: the save() function at the same time allows distinction between the two (input ranges don't define a save() function) and also allows ranges to be implemented as classes as well as structs. > > To summarize: > > Input ranges: empty front popFront > > Forward ranges: + save > > Bidir ranges: + back popBack > > Random-access ranges: + opIndex opIndexAssign > > The disadvantage is that all non-input ranges must define save(), which is a trivial functions in most cases: > > Range save() { return this; } I have two questions that came to mind: 1. What is the use case for classes as ranges? I can't think of one. With structs, you can control the aliasing behavior when it is copied, so the issue is less critical. 2. Even if there is a use case, why put the band-aid on the ranges that aren't affected? That is, why affect all ranges except input ranges when input ranges are the issue? Even if this does work, you are going to have mistakes where you copy the range instead of calling .save, which will compile successfully. Since you have to special case it, why not just put a flag in the non-copyable input ranges? Like an enum noCopy = true; or something. Then you can special case those and have them fail to compile when they don't support the algo. For classes, you wouldn't need to do this, because they are by default reference types, and this can be statically checked. The point is, make the frequent usage easy, and the one-time range design require the careful usage. -Steve | |||
June 02, 2009 Re: forward ranges must offer a save() function | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer wrote:
> The point is, make the frequent usage easy, and the one-time range design require the careful usage.
>
> -Steve
+1 this. easy to do the right thing, hard to the wrong thing.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply