tc39 / proposal-seeded-random

Proposal for an options argument to be added to JS's Math.random() function, and some options to start it with.
MIT License
156 stars 6 forks source link

Provide simpler API for retrieving individual values #9

Closed davidje13 closed 5 years ago

davidje13 commented 5 years ago

The current API:

const prng = Math.seededPRNG({seed:0});
for(const [i,r] of enumerate(prng)) {
  // do something with each value
  if(i >= limit) break;
}

Is very verbose for situations where a small, fixed number of random numbers are needed (e.g. an x/y coordinate pair):

const prng = Math.seededPRNG({seed:0});
const randomX = prng.next().value;
const randomY = prng.next().value;

// compare:
const randomX = Math.random();
const randomY = Math.random();

I see the appeal of returning a generator, but this is nothing like the existing Math.random API.

I suggest either replacing or augmenting (if possible) the proposed API by making the returned value callable:

const prng = Math.seededPRNG({seed:0});
for(let i = 0; i < limit; i ++) {
  const r = prng();
  // do something with each value
}

Which makes more sense for fixed numbers of values:

const prng = Math.seededPRNG({seed:0});
const randomX = prng();
const randomY = prng();

// compare:
const randomX = Math.random();
const randomY = Math.random();

The main benefit is that the API is fully consistent and familiar, and Math.random could even be just an instance of the PRNG object (though it would likely just share the API rather than the implementation since I imagine some implementations already try to make it more random than a deterministic PRNG).

tabatkins commented 5 years ago

Yeah, I think this is probably the way to go. I thought I was being clever with the generator, but actually using it in a loop is a little weird, you can't spread it, and it's annoying to use for single values.

You can trivially create a generator version of one, of course:

function* genRandom(args) {
  const prng = Math.seededPRNG(args);
  while(1) yield prng();
}

so I don't think it's particularly necessary to provide a generator by default.

(though it would likely just share the API rather than the implementation since I imagine some implementations already try to make it more random than a deterministic PRNG).

Interestingly, that's not the case; due to silly microbenchmarks promoting a race to the bottom, Math.random() is forced to use a fast, insecure random algorithm in all browsers. The Crypto API is how you get good randomness.

That said, people do want the ability to do a quick and easy Math.random = Math.seededPRNG(...); and then just pretend like Math.random() is good, and this API change would allow that.

tabatkins commented 5 years ago

Done, the returned value is now just an opaque object with a .random() method.