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
Sat Jun 20 16:41:35 UTC 2020


On Saturday, 20 June 2020 at 14:51:32 UTC, Andrei Alexandrescu 
wrote:
> On 6/20/20 5:49 AM, Stanislav Blinov wrote:
>> On Saturday, 20 June 2020 at 04:34:42 UTC, H. S. Teoh wrote:
>>> On Fri, Jun 19, 2020 at 09:14:30PM -0400, Andrei Alexandrescu 
>>> via Digitalmars-d wrote: [...]
>>>> One good goal for std.v2020 would be to forego autodecoding 
>>>> throughout.
>>> [...]
>>>
>>> Another could be to fix up the range API -- i.e, reconsider 
>>> the ugliness that is .save, now that D has copy ctors.
>> 
>> How do you see that? Fundamentally, what have copy ctors 
>> changed in this regard?
>
> I've been thinking of this for a while. The fact that input 
> ranges must buffer one element (i.e. make front() callable 
> several times) has been a gauche choice.

I think there's a bit of conflation going on here. Being able to 
call front() several times does not necessitate the *range* being 
buffering. After all, the range, generally speaking, need not 
store any data at all. Buffering comes as a necessity for some 
*data sources*, which are either slow to fetch the data, or 
simply don't have it yet, not unlike the one you're showing below:

> Input ranges should have only one API:
>
> bool fetchNext(T& target);
>
> Fill the user-provided target with the next element and return 
> true. At the end of the range, return false and leave the 
> target alone.

For anything other than PODs, this API is less efficient and 
forces the callers to, effectively, do busy work (i.e. 
boilerplate just to facilitate language plumbing).

while (!range.empty)
{
     dataStructure.emplace(range.front); // *
     range.popFront();
}

As far as the range API itself is concerned, the above line (*), 
under Walter's "moving" proposal, is *at most* a constructor call 
and a move-construct (or just the constructor call, in a good 
optimizing compiler with the right data structure 
implementation), and *no* (zero!) destructor calls. Mind you, the 
`front` need not, necessarily, be returning a copy. Consider e.g. 
a range consuming a socket: it'd just construct the element out 
of buffered data and return it with NRVO (IOW, construct it 
directly on caller's stack, or, potentially, straight in the 
`dataStructure`).

Versus this:

while (true)
{
     ElementType tmp = ElementType.init;
     if (range.fetchNext(tmp)) // That's a copy-assign, i.e. a 
(redundant) dtor + copy
         dataStructure.emplace(move(tmp)); // one (or two) 
move-constructs
     else
         break;
} // redundant dtor

I am by no means an expert on compilers, but something tells me 
that eliding redundant calls and copies from *that* isn't a task 
for the light-hearted.

I'll take a "buffering" API over that any day. Not that the 
`fetchNext` API doesn't have its uses (it absolutely does), I 
just don't think it's a good candidate for ranges.


More information about the Digitalmars-d mailing list