Preferred behavior of take() with ranges (value vs reference range)

TheFlyingFiddle via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Nov 8 18:44:47 PST 2015


On Monday, 9 November 2015 at 02:14:58 UTC, Jon D wrote:
> Here's an example of the behavior differences below. It uses 
> refRange, but same behavior occurs if the range is created as a 
> class rather than a struct.
> --Jon

This is an artifact of struct based ranges being value types. 
When you use take the range get's copied into another structure 
that is also a range but limits the number of elements you take 
from that range.

Basically: take looks something like this: (simplified)

struct Take(Range)
{
    size_t count;
    Range  range;

    @property ElementType!Range front() { return range.front; }
    @property bool empty() { return count == 0 || range.empty; }
    void popFront() { count--; range.popFront; }
}

Code like this:

auto fib1 = ...

//Here fib1 get's copied into first5.
auto first5 = Take(5, fib);

So later when you perform actions on first5 you no longer take 
any action on fib1 but instead take action on the copied range 
inside of first5. Hence you don't see any consumption of fib1's 
elements.

However when you use a refRange / a class the Take range will 
take a reference / pointer to the actual range. So now your no 
longer working a copy of the range but on the range itself. As 
you reuse the same range you will see that consumption has 
occured.

If you want a more indepth explanation there were two talks at 
Dconf this year that (in part) discussed this topic. 
(https://www.youtube.com/watch?v=A8Btr8TPJ8c, 
https://www.youtube.com/watch?v=QdMdH7WX2ew&list=PLEDeq48KhndP-mlE-0Bfb_qPIMA4RrrKo&index=14)


More information about the Digitalmars-d-learn mailing list