More tricky range semantics

Joseph Rushton Wakeling via Digitalmars-d digitalmars-d at puremagic.com
Fri Jan 16 08:12:22 PST 2015


On Friday, 16 January 2015 at 14:59:10 UTC, Dicebot wrote:
> To specify : the way I see it you either want PRNG to be a 
> forward range and that fits with value semantics. Or you want 
> reference semantics and it naturally becomes input range.

Here's the problem with value semantics.  This is a real problem 
with actual Phobos code right now.

////////////////////////////////////////////////////
import std.random, std.range, std.stdio;

void main()
{
     // Create RNG instance with unpredictable seed
     auto rng = Random(unpredictableSeed);

     // Generate sample of 3 numbers from sequence
     // 0, 1, ..., 9 using rng as source of randomness
     // and write to console
     iota(0, 10).randomSample(3, rng).writeln;

     // Do again.  We'd expect a different result
     // but actually we get just the same
     iota(0, 10).randomSample(3, rng).writeln;
}
////////////////////////////////////////////////////

Note that because randomSample generated a wrapper range 
(RandomSample), we can't simply pass the RNG by ref.  It's copied 
(and because RNGs are currently value types, it's copied by 
value).

Note also that the above is a problem whether or not Random is a 
forward or input range.

What's needed here is for the source of randomness to be updated 
whenever it's used, so that you don't get unintended correlations 
like this.  Reference types give this, but it shouldn't be 
necessary to interfere with the forward-range status of the RNG, 
which depends entirely on whether it's a deterministic pseudo-RNG 
or not.

Conversely, suppose that we have some function that takes a 
forward range as input and uses the ability to repeat the 
sequence.  Here's a naive example:

void foo (FRange) (FRange range)
     if (isForwardRange!FRange)
{
     foreach (i; 0 .. 10)
     {
         // silly example :-P
         auto r = range.save;
         r.take(10).writeln;
     }
}

This is a problematic design if FRange is a reference type, 
because (by design) if the values in it are used, they should be 
consumed.  So e.g. if you were passing a reference-type RNG to a 
function that does this, you'd like to guarantee that (i) the 
function is able to use the ability to repeat the sequence, but 
(ii) consumes from the original exactly once.

If you don't get that, you will wind up with unintended 
correlations in your use of random numbers.


More information about the Digitalmars-d mailing list