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