Difference between range `save` and copy constructor

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Feb 16 17:10:24 UTC 2020


On Sunday, February 16, 2020 7:29:11 AM MST uranuz via Digitalmars-d-learn 
wrote:
> On Sunday, 16 February 2020 at 12:38:51 UTC, Jonathan M Davis
>
> wrote:
> > On Sunday, February 16, 2020 3:41:31 AM MST uranuz via
> >
> > Digitalmars-d-learn wrote:
> >> I have reread presentation:
> >> http://dconf.org/2015/talks/davis.pdf
> >> We declare that `pure` input range cannot be `unpoped` and we
> >> can't return to the previous position of it later at the time.
> >> So
> >> logically there is no sence of copying input range at all. So
> >> every Phobos algorithm that declares that it's is working with
> >> InputRange must be tested for working with range with disabled
> >
> > A range that can't be copied is basically useless. Not only do
> > almost all range-based algorithms take their argumenst by value
> > (and thus copy them), but foreach copies any range that it's
> > given, meaning that if a range isn't copyable, you can't even
> > use it with foreach. And since many range-based algorithms
> > function by wrapping one range with another, the ability to
> > copy ranges is fundamental to most range-based code.
>
> This is working fine with disabled postblit...
> import std;
>
> struct SS
> {
>      @disable this(this); // Disabled copy
>
>      bool _empty = false;
>
>      bool empty() @property {
>          return _empty;
>      }
>
>      void popFront() {
>         _empty = true;
>      }
>
>      int front() @property { return 10; }
> }
>
>
> void main()
> {
>      foreach( it; SS() ) { writeln(it); }
> }
>
> Am I missing something?

That code compiles, because you're passing a temporary to foreach. So, the
compiler does a move instead of a copy. It's the difference between

auto ss = SS();

and

SS ss;
auto ss2 = ss;

If your main were

    void main()
    {
        SS ss;
        foreach( it; ss ) { writeln(it); }
    }

then it would not compile.

    foreach(e; range) {...}

basically gets lowered to

    for(auto __r = range; !__r.empty; __r.popFront())
    {
        auto e = __r.front;
        ...
    }

So,

    foreach( it; SS() ) { writeln(it); }

would become

    for(auto __r = SS(); !__r.empty; __r.popFront())
    {
        auto it = __r.front;
        writeln(it);
    }

whereas

    SS ss;
    foreach( it; ss ) { writeln(it); }

would become

    SS ss;
    for(auto __r = ss; !__r.empty; __r.popFront())
    {
        auto it = __r.front;
        writeln(it);
    }

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list