[swift-evolution] [Proposal] Random Unification

Xiaodi Wu xiaodi.wu at gmail.com
Wed Oct 4 21:25:54 CDT 2017

On Wed, Oct 4, 2017 at 21:01 Xiaodi Wu <xiaodi.wu at gmail.com> wrote:

> On Wed, Oct 4, 2017 at 20:49 Greg Parker via swift-evolution <
> swift-evolution at swift.org> wrote:
>> On Oct 3, 2017, at 11:44 PM, Jonathan Hull via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> I like the idea of splitting it into 2 separate “Random” proposals.
>> The first would have Xiaodi’s built-in CSPRNG which only has the
>> interface:
>> On FixedWidthInteger:
>> static func random()throws -> Self
>> static func random(in range: ClosedRange<Self>)throws -> Self
>> On Double:
>> static func random()throws -> Double
>> static func random(in range: ClosedRange<Double>)throws -> Double
>> (Everything else we want, like shuffled(), could be built in later
>> proposals by calling those functions)
>> The other option would be to remove the ‘throws’ from the above functions
>> (perhaps fatalError-ing), and provide an additional function which can be
>> used to check that there is enough entropy (so as to avoid the crash or
>> fall back to a worse source when the CSPRNG is unavailable).
>> Then a second proposal would bring in the concept of RandomSources
>> (whatever we call them), which can return however many random bytes you ask
>> for… and a protocol for types which know how to initialize themselves from
>> those bytes.  That might be spelled like 'static func random(using:
>> RandomSource)->Self'.  As a convenience, the source would also be able to
>> create FixedWidthIntegers and Doubles (both with and without a range), and
>> would also have the coinFlip() and oneIn(UInt)->Bool functions. Most types
>> should be able to build themselves off of that.  There would be a default
>> source which is built from the first protocol.
>> I also really think we should have a concept of Repeatably-Random as a
>> subprotocol for the second proposal.  I see far too many shipping apps
>> which have bugs due to using arc4Random when they really needed a
>> repeatable source (e.g. patterns and lines jump around when you resize
>> things). If it was an easy option, people would use it when appropriate.
>> This would just mean a sub-protocol which has an initializer which takes a
>> seed, and the ability to save/restore state (similar to CGContexts).
>> I like this kind of layering of functionality and proposals. I would
>> additionally separate the fundamental CSPRNG interface from the fool-proof
>> easy functions that naive users will find on Stack Overflow.
>> The "easy" functions should:
>> * Trap on any error without throwing. Sophisticated users may be able to
>> do something about entropy failure, so the fundamental CSPRNG interface
>> needs to provide errors, but the easy function should either degrade
>> somewhat (if entropy is present but insufficient) or just die (if entropy
>> is wholly absent or nearly so).
>> * Remove the range-less function. Naive users often write things like
>> `Int.random() % 100`, which unbeknownst to them is biased. Providing only
>> the ranged interface nudges naive users toward correct usage.
>> * Provide an "easy" way to get some random bytes instead of a random
>> number. Perhaps a Data initializer that returns random-filled bytes of the
>> requested length. This helps make up for the lack of a range-less function
>> on FixedWidthInteger.
>> The "easy" functions should get the best names: Int.random(in:),
>> Data.random(length:), etc. The fundamental CSPRNG interface should have an
>> interface that is less friendly and less discoverable.
> Agree, this is a very tractable set of functions for an initial
> implementation. In fact, with these primitives and maybe some shuffling and
> choosing conveniences in the stdlib, I see the remainder as useful-to-haves
> that may or may not be critical for inclusion in the stdlib vs more
> appropriate for a dedicated math library (more to follow on that thought in
> a little while).

To sum up my thoughts so far in code, building on previous comments from
others, this would be a nice set of random APIs, IMO:

extension Int {
  static func random(in range: Countable{Closed}Range<Int>) -> Int
// And similar for other concrete built-in integer types.
// Since fixed-width integers could exceed the maximum size supported by
// and other such functions, we do not provide a default implementation.
// The return value may not be cryptographically secure if there is
insufficient entropy.

extension Float {
  static func random(in range: {Closed}Range<Float>) -> Float

extension Double {
  static func random(in range: {Closed}Range<Double>) -> Double

extension Float80 {
  // Ditto.

extension Data {
  static func random(byteCount: Int) -> Data

extension UnsafeMutableRawPointer {
  func copyRandomBytes(count: Int) throws
// This function is to be the most primitive of the random APIs, and will
throw if there is insufficient entropy.

extension UnsafeMutableRawBufferPointer {
  func copyRandomBytes() throws
// Just as UMRBP.copyBytes(from:) parallels UMRP.copyBytes(from:count:), we
offer this convenience here.

>> --
>> Greg Parker     gparker at apple.com     Runtime Wrangler
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171005/b37d06d5/attachment.html>

More information about the swift-evolution mailing list