On 6/12/16 4:46 AM, Dicebot wrote:
On Friday, 3 June 2016 at 12:03:26 UTC, Steven Schveighoffer wrote:

Yes, I can see good reason why you would want this. Hm... a set of
adapters which reduce a range to its lesser API would be useful here:

array.asInput.map

But an expectation for map should be that you want it to be exactly
the same as the original, but with a transformation applied to each
fetch of an element. I think it needs to provide random access if
random access is provided to it.

That is matter of design philosophy. For me such basic library
primitives warrant C++ attitude of "don't pay for what you don't ask
for" - and everything else, including actual feature completeness, is of
negligible importance compared to that. If keeping random access for map
requires either caching or multiple evaluations of predicate, I want it
to be banned by default and enabled explicitly (not sure what could be
good API for that though).

So what it seems like you want is somerange.map(...).front to evaluate the lambda only once, without caching. This doesn't fit into the definition of ranges, which require the ability to access the same front more than once.

What you really want is a new kind of construct. It's not a range.

Given that front must be accessible more than once, map has to make a choice, caching or reevaluating. Not doing one of those two things is not an option for ranges.

Note that this has nothing to do with random access.

Phobos indeed doesn't seem to make such priorities right now and that is
one of reasons I am growing increasingly unhappy with it.

It's not so much that Phobos attempts to give you kitchen sink support at all costs, it's that if the sink being passed in has all the faucets, it'll forward them for free if possible.

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

Good advice. Don't want bugs with non-stable results and accidental
double I/O in your long idiomatic range pipeline? Just put "cache" calls
everywhere just to be safe, defensive programming for the win!

Strawman, not what I said.

But that is what your answer meant in context of my original question :)
My complaint was about existing semantics are being error-prone and hard
to spot - you proposed it by adding more _manual_ fixup, which kills the
whole point.

No, it's not. My advice is to understand the limitations and expectations of the range wrappers you are using (i.e. read the docs [1]). If you need caching for your purposes, then do that by plopping cache at the end of your use case. The user must have to understand that providing a mapping function that does random things (or even varying things on each call) is going to result in unexpected behavior. The compiler cannot foresee the purpose of your lambda code.

You just said only pay for what you ask for. I don't want to pay for caching for map if I don't need it. I'd be pissed if map cached for something like map!(x => x * 2). If you want caching, then ask for it.

There was a talk by Herb Sutter on atomic operations on various platforms. His general rule was, as long as you don't write race conditions, and use only provided atomics, your code will do what you think. We can apply a similar rule here: as long as you write a lambda which for a given input will provide the same result, map will do what you expect. When you try odd things like your random call, we don't guarantee things will work like you expect. You may utilize the knowledge of how map works, and how the things that are using the map work to write something clever that breaks the rules. But no guarantees.

-Steve

[1] I admit, the map docs aren't explicit about this, and should be.

Reply via email to