Rename `FixedWidthInteger._random()` to `FixedWidthInteger.random(in: UnboundedRange)`

On master branch, we have FixedWidthInteger._random() function for sampling random numbers from full range.

I think we should have FixedWidthInteger.random(in: UnboundedRange) for this purpose.

  1. There is FixedWidthInteger.random(in: Range<Self>) function. So adding UnboundedRange version makes API more consistent.
  2. If someone misses _random(), he may use FixelWidthInteger.random(in: 0 ... .max). Not only it looks ugly, Range version is a bit slower than _random(). Having no underscored random leads him better way.
  3. If we have no arguments FixedWidthInteger.random(), someone may wonder why we don't have no arguments BinaryFloatingPoint.random() for [0, 1) range. FixedWidthInteger.random(in: UnboundedRange) won't cause such confusion.

I don't know why this function is underscored. But even if it's not underscored, I believe random(in: UnboundedRange) is much better than random() and well fit for Swift.

2 Likes

The underscored API is non-public according to the standard library convention. The pull request discussion and commit message explain why it was added.

As for overloading .random(in:) and .random(in:using:) to support UnboundedRange, there might still be confusion between 0 ... .max and .min ... .max for signed integers. Otherwise, why not also support the other range types?

PartialRangeUpTo    (prefix  ..<)
PartialRangeThrough (prefix  ...)
PartialRangeFrom    (postfix ...)

I see.
It is originally added as a part of FixedWidthInteger but the requirement was removed. Now it's used only in RandomNumberGenerator.next() despite its usefulness.

Signed integer confusion is conceivable. For them, PartialRangeFrom version may be well fit.

But at least we can have UnsignedInteger.random(in: UnboundedRange).
For full range generation we must choose UInt.random(in: 0 ... .max) or Random.default.next(). The former is I described in the first post and the latter will be renamed to longer name.

If we want signed/unsigned integers to have common interface/implementation, simply renaming_random to random is an option.

It seems Random API doesn't encourage using Random.default explicitly. So having alternative for Random.default.next() may fit the policy.

This was rejected in the SE-0202 proposal.

Add static .random() to numerical types

There's also an issue with how UnboundedRange is currently implemented.

1 Like

The lack of a full-width random number implementation was an intentional and conscious choice made during the recent adoption of the new random number API.

The need for a true full-width random number was considered fairly rare, and the risk of that full-width API being misused (in the same way arc4random was, by following it up with a % that introduces bias) outweighed it.

The most common need for a full-width random integer is to generate a longer sequence of randomness (i.e. filling a buffer with random bytes). But most sources of randomness could probably do this better if asked directly. A solution to this that had the support as a follow-up proposal when the original API was adopted was adding a buffer-populating API to the random generator protocol.

Do you have benchmarks showing this? If the cost is significant, we should investigate whether the optimizer is able to eliminate the cost, since a lot of it ought to constant-fold when supplied with the full-width min and max.

6 Likes

I’ve been really busy these past few weeks, but I’m looking forward to pitching this and other improvements to RandomNumberGenerator soon™

1 Like

I thought Range version may have some overheads. I benchmarked and found there isn't significant differences at all.
I'm sorry for lack of inspection.