<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Sep 8, 2017, at 2:46 PM, Jacob Williams via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">What if we did it with something like this:</span><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">protocol RandomGenerator {</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="Apple-tab-span" style="white-space: pre;">        </span>associated type T: Numeric // Since numeric types are the only kinds where we could get a random number?</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="Apple-tab-span" style="white-space: pre;">        </span>func uniform() -> T</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="Apple-tab-span" style="white-space: pre;">        </span>// Other random type functions...</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">}</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Although if we didn’t constrain T to Numeric then collections could also conform to it, although I’m not sure that collections would want to directly conform to this. There may need to be a separate protocol for types with Numeric indexes?</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">I’m no pro and really haven’t thought about this too deeply. Mostly just spitballing/brainstorming.</div></div></blockquote><br class=""></div><div>I think I would simply say:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// Conforming types generate an infinite sequence of random bits through their `next()` method.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// They may be generated from a repeatable seed or from a source of true entropy.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>protocol Randomizer: class, IteratorProtocol, Sequence where Element == UInt, Iterator == Self {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>/// Generates and returns the next `UInt.bitWidth` bits of random data.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func next() -> UInt</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>And have this extension on it:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>extension Randomizer {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>/// Permits the use of a Randomizer as a plain old iterator.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func next() -> UInt? {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>return Optional.some(next())</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">                </span></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>/// Returns a number in the range 0 ... maximum.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>/// (This is inclusive to allow `maximum` to be `UInt.max`.)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func next(through maximum: UInt) -> UInt {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>…</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>We should also provide a singleton `StrongRandomizer`:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// A source of cryptographically secure random data.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// `StrongRandomizer` typically uses the strongest random data source provided by </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// the platform that is suitable for relatively frequent use. It may use a hardware RNG </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// directly, or it may use a PRNG seeded by a good entropy source.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// `StrongRandomizer` is inherently a singleton.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// It can be used on multiple threads, and on some platforms it may block while its </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/// shared state is locked.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>class StrongRandomizer: Randomizer {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>static let shared = StrongRandomizer()</div><div><span class="Apple-tab-span" style="white-space:pre">                </span></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func next() -> UInt {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>…</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>Finally, we can add extensions to `RandomAccessCollection`:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>extension RandomAccessCollection {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func randomElement(with randomizer: Randomizer = StrongRandomizer.shared) -> Element? {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>guard !isEmpty else { return nil }</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>let offset = IndexDistance(randomizer.next(through: UInt(count) - 1))</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>return self[index(startIndex, offsetBy: offset)]</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>And ranges over `BinaryFloatingPoint`:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>extension Range where Bound: BinaryFloatingPoint {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>func randomElement(with randomizer: Randomizer = StrongRandomizer.shared) -> Bound? {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>…</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension ClosedRange where Bound: BinaryFloatingPoint {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>func randomElement(with randomizer: Randomizer = StrongRandomizer.shared) -> Bound {</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>…</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">A couple of notes:</div><div class=""><br class=""></div><div class="">• Fundamentally, a randomizer is an infinite sequence of random-ish bits. I say "random-ish" because you may be generating a repeatable pseudo-random sequence from a seed. But in any case, I think it's best to envision this as a special case of an iterator—hence the `IteratorProtocol` conformance.</div><div class=""><br class=""></div><div class="">• Randomizer is class-constrained because we want to encourage providing a defaulted parameter for the randomizer, and `inout` parameters can't be defaulted.</div><div class=""><br class=""></div><div class="">• `UInt` is intentionally inconvenient. You should not usually use a randomizer directly—you should pass it to one of our methods, which know how to handle it correctly. Making it awkward discourages direct use of the randomizer.</div><div class=""><br class=""></div><div class="">• `next(through:)` is provided simply to discourage incorrect modulo-ing.</div><div class=""><br class=""></div><div class="">• `StrongRandomizer` is provided as a slow but safe default. I don't think we should ship any other RNGs; people who want them can import them from modules, which provides at least a bit of evidence that they know what they're doing. (Actually, I could see adding a second RNG that's even stronger, and is specifically intended to be used infrequently to generate seeds or important cryptographic keys.)</div><div class=""><br class=""></div></div><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">-- </div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>
</div>
<br class=""></body></html>