Transient ranges

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Tue May 31 18:31:53 PDT 2016


On 5/31/16 4:59 PM, Dicebot wrote:
> On Tuesday, 31 May 2016 at 18:11:34 UTC, Steven Schveighoffer wrote:
>>> 1) Current definition of input range (most importantly, the fact `front`
>>> has to be @property-like) implies `front` to always return the same
>>> result until `popFront` is called.
>>
>> Regardless of property-like or not, this should be the case.
>> Otherwise, popFront makes no sense.
>
> Except it isn't in many cases you call "bugs" :(

If you want to use such "ranges", the compiler will not stop you. Just 
don't expect any help from Phobos.

>>> 2) For ranges that call predicates on elements to evaluate next element
>>> this can only be achieved by caching - predicates are never required to
>>> be pure.
>>
>> Or, by not returning different things from your predicate.
>
> It is perfectly legal for predicate to be non-pure and that would be
> hugely annoying if anyone decided to prohibit it. Also even pure
> predicates may be simply very expensive to evaluate which can make
> `front` a silent pessimization.

There's no requirement or need to prevent it. Just a) don't do it, or b) 
deal with the consequences.

>
>> This is like saying RedBlackTree is broken when I give it a predicate
>> of "a == b".
>
> RBL at least makes certain demands about valid predicate can be. This is
> not case for ranges in general.

RedBlackTree with "a == b" will compile and operate. It just won't do 
much red-black-tree-like things.

>>> 3) But caching is sub-optimal performance wise and thus bunch of Phobos
>>> algorithms violate `front` consistency / cheapness expectation
>>> evaluating predicates each time it is called (liked map).
>>
>> I don't think anything defensively caches front in case the next call
>> to front is different, unless that's specifically the reason for the
>> range.
>
> And that makes input ranges violate implication #1 (front stability)
> casually to the point it can't be relied at all and one has to always
> make sure it is only evaluated once (make stack local copy or something
> like that).

That's a little much. If you expect such things, you can construct them. 
There's no way for the functions to ascertain what your lambda is going 
to do (halting problem) and determine to cache or not based on that.

>> I think we should be aware that the range API doesn't prevent bugs of
>> all kinds. There's only so much analysis the compiler can do.
>
> This is a totally valid code I want to actually work and not be
> discarded as "bug".

Then it's not a bug? It's going to work just fine how you specified it. 
I just don't consider it a valid "range" for general purposes.

You can do this if you want caching:

only(0).map!(x => uniform(0, 10)).cache

-Steve


More information about the Digitalmars-d mailing list