std.v2020.algorithm etc[ WAS: Is run.d going to be expand for runtime and the phobos library?]

Stanislav Blinov stanislav.blinov at gmail.com
Wed Jun 24 15:26:40 UTC 2020


On Wednesday, 24 June 2020 at 13:14:22 UTC, Paul Backus wrote:
> On Wednesday, 24 June 2020 at 11:49:11 UTC, Stanislav Blinov 
> wrote:
>> On Monday, 22 June 2020 at 16:03:54 UTC, Andrei Alexandrescu 
>> wrote:
>>> It is quite clear to me that we can't propose a design with 
>>> noncopyable input ranges without effectively making them 
>>> pariahs that everybody will take pains to use and do their 
>>> best to avoid.
>>
>> Then we should propose a design that is not painful to use:
>>
>> // error: `input` cannot be copied
>> // auto data = input.filter!somehow.map!something.array;
>> // Ok:
>> auto data = input.move.filter!somehow.map!something.array;
>>
>> If we need partial consumption, i.e. preservation of the 
>> remainder, terminal primitives can give it back to us (after 
>> all, wrapping range is holding onto it):
>>
>> auto data = 
>> input.move.filter!somehow.take(someAmount).map!something.array(input);
>
> IMO if the user has to manually call `move`, you have already 
> failed at usability.
>
> It may seem "easy" or "obvious" to you and I, but for 
> beginners, this is going to be a huge stumbling block.

Libraries shan't be for "beginners" nor "advanced users". And 
that use case is already a non-beginner. Beginners would write 
this:

auto data = 
createSomeInput(args).filter!somehow.map!something.array;

Create input, consume input, with no explicit moves in sight. 
Piecemeal consumption of an input range is something an 
"advanced" user would be doing :)

I am also of the opinion that a huge reminder "YOU SHALL NOT COPY 
UNLESS YOU MUST" needs to be present on every page of any 
introductory (and not only) literature, and not just for D. The 
problem with lax copying extends far outside the realm of ranges.

struct CopyCount
{
     int count;
     this(ref typeof(this) other) { count = other.count + 1; }
}

CopyCount cc;
writeln(cc);

In my book, that should print CopyCount(0) (i.e. you print that 
which you can parse and get the original). That's not what Phobos 
writeln would print though. It won't even print CopyCount(1).

People need to be taught to not squander their values, and how 
not to.

> You write some code that looks like it should obviously work, 
> you get a mysterious error message that 
> "std.algorithm.whatever!(some, args).Result is not copyable 
> because it is annotated with @disable"

Yup, because in that hypothetical universe you're using a type 
that is documented to be an input range, a category of ranges 
which is documented to be non-copyable, which means you just 
wrote what otherwise would've been a bug, but the compiler 
stopped you.

> and the solution is that you have to add ".move" to your code? 
> Can you imagine having to explain that to someone in the Learn 
> forum? I don't think I could do it with a straight face--it's 
> too absurd.

Nothing to it - you point such user to the documentation of 
ranges which states that input ranges are non-copyable, explains 
why they're non-copyable, and has usage examples for rvalues and 
lvalues.
You're aware of a recent question in .learn there, where the user 
attempted to iterate a non-copyable range (the thread which 
turned into another prolonged discussion: 
https://forum.dlang.org/post/kpncjzadrwpvxupsdmle@forum.dlang.org). A range which, by the way, was an input range. The explanations quickly went into "common pitfalls" territory. Jonathan M Davis' response was of particular interest: "In general, you should never use a range after it's been copied unless you know exactly what type of range you're dealing with and what its copying behavior is. If you want an independent copy, you need to use save."
I don't think explaining that to a "beginner" is more practical 
than explaining that input ranges are consumed once and may be 
yielding values that are only valid between iterations.

> The only way non-copyable input ranges can work is if the 
> compiler is able to implicitly move them in cases like the 
> above. In other words, we would need something like Walter's 
> "Copying, Moving, and Forwarding" DIP [1].
>
> [1] 
> https://github.com/WalterBright/DIPs/blob/13NNN-WGB.md/DIPs/13NNN-WGB.md

The way that proposal exists at the moment, it won't help 
practically whenever you're not at "last use" (i.e. the second 
case - wanting to keep the lvalue for the remainder). Compiler 
will want to copy then. It'll certainly help for the first case 
though, as well as general implementation of ranges.


More information about the Digitalmars-d mailing list