std.range.cacheFront proposal&working code: wraps a range to enforce front is called only once

Jonathan M Davis jmdavisProg at gmx.com
Thu Oct 24 10:57:43 PDT 2013


On Thursday, October 24, 2013 09:56:24 Timothee Cour wrote:
> that changes semantics: what if you want to do some actions before and
> after accessing the front element. You'd have to do quite a big of
> gymnastics to do that in popFront:
> eg:
> elements.map!( (a) {preaction(a); auto b=transform(a); postaction(a,b);
> return b;}) . filter/sort/map/etc
> 
> With what I proposed, it is possible, and it guarantees the lambda will be
> called once at most per element.

And why are you doing these preactions or postactions inside of something like 
map? IMHO, doing anything that doesn't involve creating the new front should 
be done outside of map.

Now, that being said, I'd argue that map should probably be changed so that it 
calls its function on popFront rather than front (though that has the downside 
of requiring that it then hold the current value, which it doesn't currently 
have to do), but regardless, you're using map for something other than what it 
was designed to do. It makes no guarantees of how many times the function you 
pass it will be called, so while it should minimize the number of calls for 
efficiency's sake, it's just wrong to rely on it being called only once. There 
is _nothing_ about ranges which makes such a guarantee (and map follows the 
standard range semantics without providing any additional guarantees). 
Logically, there is no difference between front as member function or as a 
member variable, and it should act like a member variable - which means no 
side effects. At most, it should be calculating the current value of front, but 
ideally, that value would be stored in order to avoid hidden costs when front 
ends up being called multiple times between calls to popFront.

You're obviously free to create wrappers around your ranges which do things 
like cache the value of front and don't call front on the wrapped range more 
than once per call to popFront, but when you require such a wrapper, you're 
violating the basic concept of how front is supposed to work per the standard 
range semantics. front is supposed to either be a member variable or to 
emulate the semantics of one, and than means no side effects. IMHO, if what
you're doing requires side effects in front, then you really need to rethink
how you're using ranges.

- Jonathan M Davis


More information about the Digitalmars-d mailing list