Proposal: takeFront and takeBack

Dmitry Olshansky dmitry.olsh at gmail.com
Tue Jul 3 11:52:41 PDT 2012


On 03-Jul-12 20:37, Jonathan M Davis wrote:
> This seems like it probably merits a bit of discussion, so I'm bringing it up
> here rather than simply opening a pull request.
>
> At present, for some ranges (variably-lengthed ranges such as strings in
> particular), calling front incurs a cost which popFront at least partially
> duplicates. So, the range primitives are inherently inefficient in that they
> force you to incur that extra cost as you iterate over the range. Ideally,
> there would be a way to get front and pop it off at the same time so that you
> incur the cost only once (either that or have front cache its result in a way
> that lets it avoid the extra cost in popFront when popFront is called - though
> that wouldn't work with strings, since for them, the range primitives are free
> functions). So, I'm proposing takeFront and takeBack:
>

I was about to propose fetchFront/fetchBack with similar semantics. 
Thanks for pushing this proposal it looks good.

My initial intent however was to add Variable Length Range as a concept. 
... Now I think binary predicate hasFetch a-la hasSlicing is better.

> https://github.com/jmdavis/phobos/commit/5bfa8126fa14a539fee67807821ec0a10503f27b
>
> For most ranges, takeFront does this:
>
> auto takeFront(R)(ref R range)
>      if(isInputRange!R && !isNarrowString!R)
> {
>      assert(!range.empty);
>      auto retval = range.front;
>      range.popFront();
>      return retval;
> }
>

Aye. Yet there is indeed a problem with pseudo-ranges that reuse 'slot' 
for front on each popFront. Well they always been brittle.

>
> So, for strings, it'll be more efficient to use takeFront than calling front and
> popFront separately. The idea then is that any user-defined range which can
> implement takeFront more efficiently than the default will define it. Then range-
> based functions use takeFront - e.g. range.takeFront() - and if the user-
> defined range implements a more efficient version, that one is used and they gain
> the extra efficiency, or if they don't, then the free function is used with
> UFCS, and they incur the same cost that they'd incur calling front and
> popFront separately. So, it's invisible to range-based functions whether a
> range actually implements takeFront itself. takeBack does the same thing as
> takeFront but it does it with back and popBack for bidirectional ranges.
>
> I _think_ that this is a fairly clean solution to the problem, but someone
> else might be able to point out why this is a bad idea, or they might have a
> better idea. And this will have a definite impact on how ranges are normally
> used if we add this, so I'm bringing it up here for discussion. Opinions?
> Thoughts? Insights?
>
> Oh, and if we go with this, ideally, the compiler would be updated to use
> takeFront for foreach instead of front and popFront if a range implements it
> (but still do it the current way if it doesn't). So, if typeof(range)
> implements takeFront,

Right. In fact as we've seen above with e.g. stdin.byLine not every 
range can do fetchFront correctly so it's a strict subset. That was the 
reason for current trio of basic operations BTW.


-- 
Dmitry Olshansky




More information about the Digitalmars-d mailing list