Difference between range `save` and copy constructor

Steven Schveighoffer schveiguy at gmail.com
Sat Feb 15 15:10:04 UTC 2020


On 2/15/20 9:45 AM, Jonathan M Davis wrote:
> On Saturday, February 15, 2020 7:34:42 AM MST Steven Schveighoffer via
> Digitalmars-d-learn wrote:
>> On 2/15/20 5:53 AM, uranuz wrote:
>>> I am interested in current circumstances when we have new copy
>>> constructor feature what is the purpose of having range `save`
>>> primitive? For me they look like doing basicaly the same thing. And when
>>> looking in some source code of `range` module the most common thing that
>>> `save` does is that it use constructor typeof(this) to create a new
>>> instance and use `save` on the source range:
>>> https://github.com/dlang/phobos/blob/v2.090.1/std/range/package.d
>>>
>>> So what is conceptual difference between `save` and copy contructor of
>>> range?
>>
>> Nothing. IMO, any time you are doing anything in save other than `return
>> this;`, you shouldn't have implemented it.
>>
>> The original impetus for the save requirement was so that forward ranges
>> could have a tangible checkable thing that allows introspection (does
>> the range have a save method?).
>>
>> I'm not entirely sure if disabled postblit was even available at the time.
>>
>> The correct way to do it would be to treat ranges that can be copied
>> (regardless of whether they have a copy constructor) as forward ranges,
>> and treat ones that cannot be copied as input ranges.
>>
>> But it's hard to redo ranges like this with all existing code out there.
> 
> Actually, as I understand it, the main reason that save was introduced was
> so that classes could be forward ranges. While it would be possible to use
> the postblit constructor or copy constructor with structs, that obviously
> won't work for classes - hence when save is required.

I remember the discussions as being about how an actual implementation 
detail was required, not just a mark. I remember a suggestion for just 
putting an enum isForward member in the range being rejected because of 
this.

Except people don't call save. They just copy, and it works for nearly 
all forward ranges in existence.

And a class allocating a new class for saving a forward range is a 
mislabeled "cheap" operation IMO.

> Personally, I think that we'd be better of simply requiring that forward
> rangse be copyable and force classes that want to be forward ranges to be
> wrapped by structs, but that would require reworking the range API, and it's
> far from a trivial change.

Yep.

> In practice though, classes should almost never be used as forward ranges,
> because calling save on them would requires allocating a now object, and
> that gets expensive fast. As part of testing dxml, I tested it with forward
> ranges that were classes in order to make sure that they were handled
> correctly, and their performance was absolutely terrible in comparison to
> ranges that were structs or strings.

Not surprised ;)

-Steve


More information about the Digitalmars-d-learn mailing list