Reference semantic ranges and algorithms (and std.random)

monarch_dodra monarchdodra at gmail.com
Fri Sep 21 14:37:28 PDT 2012


On Friday, 21 September 2012 at 19:47:16 UTC, Jonathan M Davis 
wrote:
> On Friday, September 21, 2012 15:20:49 monarch_dodra wrote:
>> #3
>> The only thing I'm having an issue with is "save". IMO, it is
>> exceptionally dangerous to have a PRNG be a ForwardRange: It
>> should only be saved if you have a damn good reason to do so. 
>> You
>> can still "dup" if you want (manually) (if you think that is
>> smart), but I don't think it should answer true to
>> "isForwardRange".
>
> It is _very_ crippling to a range to not be a forward range. 
> There's lots of
> stuff that requires it. And I really don't see what the problem 
> is. _Maybe_
> it's okay for them to be input ranges and not forward ranges, 
> but in general,
> I think that we need to be _very_ careful about doing that. It 
> can be really,
> really annoying when a range is not a forward range.

I know it is crippling, but that is kind of the entire point: If 
somebody wants to read the same numbers trough twice, he'd better 
have a damn good reason. For example, *even* with reference 
ranges:

----
auto rng = SomeReferenceForwardRange();
auto a = new int[](10);
auto b = new int[](10);
a.fill(rng);
b.fill(rng);
----

This will fill a and b with the *same* numbers (!), even though 
rng is a reference range (!) Arguably, the bug is in fill (and 
has since been fixed), but the point is that by the time you 
notice it, who knows how long you've debugged? And who knows 
which *other* algorithms will break your prnd?

Had the rng been only InputRange, the compilation would have 
raised an error. And the work around is also easy. Safety first, 
right?

It might not be worth deprecating *now*, but I do think it is a 
latent danger.

PS: In all of random, there is not one single use case for having 
a ForwardPrng. Just saying.

>> You just don't know what an algorithm will do under the hood if
>> it finds out the range is saveable. In particular, save can be
>> non-trivial and expensive...
>
> It shouldn't be. It's a copy, and copy's are not supposed to be 
> expensive.
> We've discussed this before with regards to postlbit 
> constructors. Certainly,
> beyond the extra cost of having to new things up in some cases, 
> they should be
> relatively cheap.

The copy of the reference is designed to be cheap (and is), yes 
(we've discussed this).

However, when you save, you have to duplicate the payload, and 
even considering that there is no postblit cost, you have 
strictly no control over its size:

LCG: 1 Int
XORShift: 5 Ints
MersenneTwister: 397 Ints
LaggedFib: (607 to 44497) ulongs or doubles

Not the end of the world, but not trivially cheap either.

>> QUESTION:
>> If I (were to) deprecate "save", how would that work with the
>> range traits type? If a range has "save", but it is deprecated,
>> does it answer true to isForwardRange?
>
> You'd have to  test it. It might depend on whether -d is used, 
> but it could
> easily be that it'll be true as long as save exists.
>
> - Jonathan M Davis

I just tested it btw:
without -d: isForwardRange: false
with    -d: isForwardRange: true

It is kind of the logical behavior actually.


More information about the Digitalmars-d mailing list