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

Timothee Cour thelastmammoth at gmail.com
Thu Oct 24 12:14:27 PDT 2013


so far you've emphasized on the fact popFront should take care of all side
effects and front should be logically pure and fast to compute, but you
haven't suggested any alternative for what I'm trying to achieve.

In what I propose it's generic (works in all cases) and simple (just add
".cacheFront" after a lambda with side effect):

auto test(T)(T elements) if(isInputRange!T){
return elements
.map!( (a) {preaction(a); auto b=transform(a); postaction(a,b); return b;})
.cacheFront
.filter!foo; //or joiner or....
}

So, how do you achieve the above without using cacheFront, without creating
a _custom_ range or writing a lot of code ?
I don't see how using foreach is a good idea (ForEachType!=ElementType, it
doesn't reuse phobos functionality and doesn't play well with phobos range
functions)








On Thu, Oct 24, 2013 at 10:57 AM, Jonathan M Davis <jmdavisProg at gmx.com>wrote:

> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20131024/b95f0080/attachment.html>


More information about the Digitalmars-d mailing list