<div dir="ltr">On Thu, Nov 30, 2017 at 5:29 PM, Jonathan Hull <span dir="ltr"><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><blockquote type="cite"><div>On Nov 30, 2017, at 2:30 PM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-7020328610336886033Apple-interchange-newline"><div><div dir="ltr" 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">On Thu, Nov 30, 2017 at 3:58 PM, Dave DeLong via swift-evolution<span class="m_-7020328610336886033Apple-converted-space"> </span><span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-<wbr>evolution@swift.org</a>></span><span class="m_-7020328610336886033Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto" style="word-wrap:break-word"><div style="word-wrap:break-word"><br><div><span><br><blockquote type="cite"><div>On Nov 30, 2017, at 2:48 PM, Jonathan Hull via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7020328610336886033m_1846945263657774348Apple-interchange-newline"><div><div style="word-wrap:break-word">I would personally go with:<div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>Int.random //Returns a random Int</div></div></div></blockquote><div><br></div></span><div>“Type.random” is so rarely used as to not be worth the addition, IMO. If you really need a random element from the *entire* domain, then I think you should have to manually create the ClosedRange<T> yourself.</div><span><br><blockquote type="cite"><div><div style="word-wrap:break-word"><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>Int.random(in: ClosedRange<Int>) //Works for Comparable types. Gives a result from the closed range. Closed Range is never empty.</div></div></div></blockquote><div><br></div></span><div>This is redundant. In order to pick a random element, you’re saying I should have to do “Int.random(0 ..< 10)”? The redundancy here is that I have to specify Int twice: once for the “.random” call, and again for the type of the range. We can do better than that.</div><span><br><blockquote type="cite"><div><div style="word-wrap:break-word"><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>[0,2,3].randomElement //Returns a random element from the collection</div></div></div></blockquote><div><br></div></span><div>I strongly believe this should be a method, not a property. Properties, like .first and .last, are expected to return the same value each time you access them. “.random” inherently breaks that.</div></div></div></div></blockquote><div> </div><div>FWIW--and this isn't a vote, I know--I largely agree with Dave DeLong's conclusions above, and for substantially the same reasons.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto" style="word-wrap:break-word"><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div style="word-wrap:break-word"><span><div><br></div><div>Then a version of each with a ‘using:’ parameter which takes a generator/source:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>Int.random(using: RandomSource) //Returns a random Int using the given source of randomness</div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>Int.random(in: ClosedRange<Int>, using: RandomSource)</div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>[0,2,3].randomElement(using: RandomSource)</div><div><br></div><div>In my own RandomSource & RandomSourceCreatable protocols, I frequently use random colors and sizes as well. The issue there is that you really want a closed range for each dimension. I wish Swift had a better notion of dimensionality baked into the language. </div><div><br></div><div>What I ended up doing was having a “constraints” parameter which took an array of constraints which corresponded to various dimensions. It works for me, but it might be a bit complex for something in the standard library.</div><div><br></div><div>Honestly, given the current capabilities of Swift what this really calls for is custom initializers/functions for dimensional types:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>UIColor.random //This comes from the protocol</div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>UIColor.random(hue: ClosedRange<CGFloat> = 0…1, saturation: ClosedRange<CGFloat> = 0…1, brightness: ClosedRange<CGFloat> = 0…1, alpha: ClosedRange<CGFloat> = 1…1)</div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>//…and of course the same as above, but with ‘using:'</div><div><br></div><div>Then you can easily get random colors which look like they belong together:</div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span></div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>let myColor = UIColor.random(saturation: 0.2…0.2, brightness: 0.6…0.6) </div><div><br></div><div>There would probably also be a convenience version taking CGFloats and passing them to the real function as ranges:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space:pre-wrap">        </span>let myColor = UIColor.random(saturation: 0.2, brightness: 0.6)</div><div><br></div><div><br></div></span><div>This means that our default RandomSource needs to be publicly available, so that the custom functions can use it as the default…</div></div></div></blockquote></div></div></div></blockquote><div><br></div><div>It does not. Having actually implemented some version of these APIs, it's readily apparent now to me that all custom types can simply call Int.random(in:) (or UnsafeRawBufferPointer<T>.<wbr>random(byteCount:), or whatever else we want to have in the standard library) to get random values from the default RNG for any built-in type and size. The actual default random need never be exposed publicly, and since its functions are strictly redundant to these other APIs (which, of course, are the "currency" APIs that our purpose here is to design and make public), the default random is required only for internal implementation of the "currency" APIs and (a) is better off *not* exposed; (b) doesn't need to be of the same type as other RNGs, conform to the same protocols, or for that matter, does not even need to be a type or be written in Swift.</div></div></div></div></div></blockquote><div><br></div><div>I have also implemented some version of these APIs, both for Random and RepeatablyRandom sources.</div><div><br></div><div>I get what you are saying about just being able to use the constructs from Int, etc…, but we still need a public default. Let me give a concrete example of CGSize. Yes, we want to just use CGFloat’s random, but if we don’t have a publicly available way to call the default then we have to implement the same algorithm twice, which is problematic. (Code written in Mail)</div><div><br></div><div>static func random(width widthRange: ClosedRange<CGFloat>, height heightRange: ClosedRange<CGFloat>, using source: RandomSource = .default) -> CGSize {</div><div><span class="m_-7020328610336886033Apple-tab-span" style="white-space:pre-wrap">        </span>let w = CGFloat.random(in: widthRange, using: source)</div><div><span class="m_-7020328610336886033Apple-tab-span" style="white-space:pre-wrap">        </span>let h = CGFloat.random(in: heightRange, using: source)</div><div><span class="m_-7020328610336886033Apple-tab-span" style="white-space:pre-wrap">        </span>return CGSize(width: w, height: h)</div><div>}</div><div><br></div><div>Without the default I would have to have a second version which used CGFloat(in:) in order to use the default source/generator, which means I would have to update both places when I make changes. Much better to just allow a default value for ‘using:'.</div></div></div></blockquote><div><br></div><div>Ah, this is assuming that one thinks it is a good idea to have `using:` variants. Firstly, I'm not entirely sold on them. But let's suppose you've convinced me. The example above illustrates a huge footgun:</div><div><br></div><div>Why do people want to use a different RNG? A very common reason: to obtain a different distribution of random values. Now, can you simply perform memberwise initialization as you show above and obtain a final instance of the desired distribution simply because the stored properties are drawn from that distribution? No no no no no! This implementation is incorrect.</div><div><br></div><div>Not only is it not _problematic_ to require two distinct implementations, it's almost certainly required if you want to have any hope of implementing them correctly.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div dir="ltr" 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"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto" style="word-wrap:break-word"><div style="word-wrap:break-word"><div><div></div><div>👍 </div><div><div class="m_-7020328610336886033h5"><br><blockquote type="cite"><div><div style="word-wrap:break-word"><div><br></div><div>Thanks,</div><div>Jon</div><div><br></div><div><br><div><blockquote type="cite"><div>On Nov 27, 2017, at 10:14 AM, TellowKrinkle via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7020328610336886033m_1846945263657774348Apple-interchange-newline"><div><div style="word-wrap:break-word">You say that all the `.random`s have different semantics, but to me (at least), they are all very similar. All the methods can be summarized as selecting a single random element from a collection<div>`[0, 2, 3].random` selects a single element from the given collection</div><div>`Int.random(in: 0…8)` selects a single element from the given range</div><div>`Int.random` has no range, but selects a single element from the collection of all ints (equivalent to if the above method had a default value for its range)</div><div>So to me these are all doing the same operation, just with different types of inputs<br><div><br><blockquote type="cite"><div>2017/11/24 20:07、Alejandro Alonso <<a href="mailto:aalonso128@outlook.com" target="_blank">aalonso128@outlook.com</a>>のメール:</div><br class="m_-7020328610336886033m_1846945263657774348Apple-interchange-newline"><div><div><div name="messageSignatureSection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"><br>- Alejandro</div><div name="messageReplySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"><br>---------- Forwarded message ----------<br><b>From:</b><span class="m_-7020328610336886033Apple-converted-space"> </span>Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>><br><b>Date:</b><span class="m_-7020328610336886033Apple-converted-space"> </span>Nov 24, 2017, 3:05 PM -0600<br><b>To:</b><span class="m_-7020328610336886033Apple-converted-space"> </span>Alejandro Alonso <<a href="mailto:aalonso128@outlook.com" target="_blank">aalonso128@outlook.com</a>><br><b>Cc:</b><span class="m_-7020328610336886033Apple-converted-space"> </span>Brent Royal-Gordon <<a href="mailto:brent@architechies.com" target="_blank">brent@architechies.com</a>>, Steve Canon via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>><br><b>Subject:</b><span class="m_-7020328610336886033Apple-converted-space"> </span>Re: [swift-evolution] [Proposal] Random Unification<br><br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(26,188,156)"><div dir="ltr">On Fri, Nov 24, 2017 at 2:55 PM, Alejandro Alonso<span class="m_-7020328610336886033Apple-converted-space"> </span><span dir="ltr"><<a href="mailto:aalonso128@outlook.com" target="_blank">aalonso128@outlook.com</a><wbr>></span><span class="m_-7020328610336886033Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(230,126,34)"><div><div name="messageBodySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif">Regarding naming too many things “random”, I’ve talked to many developers on my end and they all don’t find it confusing. This proposal is aimed to make it obvious what the operation is doing when regarding random. I still agree that the proposed solution does just that and in practice feels good to write.</div></div></blockquote><div><br></div><div>I must disagree quite strongly here. The various facilities you name "random" have different semantics, and differences in semantics should be reflected in differences in names. It doesn't matter that some people don't find it confusing; it is objectively the case that you have named multiple distinct facilities with the same name, which leads to confusion. I, for one, get confused, and you can see on this list that people are using arguments about one property named "random" to discuss another property named "random". This is quite an intolerable situation.</div><div><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(230,126,34)"><div><div name="messageBodySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"><div>I disagree that sample is the correct naming to use here. Getting a sample is a verb in this context which would make it break API guidelines just as well as `pick()`. To sample is to “take a sample or samples of (something) for analysis.” I can agree to use `sampling()` which follows API guidelines. This would result in the following grammar for `[“hi”, “hello”, “hey”].sampling(2)`, “From array, get a sampling of 2"</div></div></div></blockquote><div><br></div><div>"Sampling" is fine.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(230,126,34)"><div><div><div class="m_-7020328610336886033m_1846945263657774348h5"><div name="messageReplySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif">On Nov 23, 2017, 12:54 AM -0600, Xiaodi Wu , wrote:<br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,152,219)"><div>On Wed, Nov 22, 2017 at 23:01 Alejandro Alonso <<a href="mailto:aalonso128@outlook.com" target="_blank">aalonso128@outlook.com</a>> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div><div name="messageBodySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif">Like I’ve said, python has different syntax grammar. We have to read each call site and form a sentence from it. `random.choice([1, 2, 3])` to me this reads, “Get a random choice from array”. This makes sense. Slapping the word choice as an instance property like `[1, 2, 3].choice` reads, “From array, get choice”. What is choice? This doesn’t make sense at all to me. To me, the only good solution is `[1, 2, 3].random` which reads, “From array, get random”. I actually think most users will be able to understand this at first glance rather than choice (or any or some).</div></div></blockquote><div dir="auto"><br></div><div dir="auto">Again, my concern here is that you are proposing to name multiple things "random". If this property should be called "random"--which I'm fine with--then the static method "random(in:)" should be named something else, and the static property "random" should be dropped altogether (as I advocate for reasons we just discussed) or renamed as well. It is simply too confusing that there are so many different "random" methods or properties. Meanwhile, isn't your default RNG also going to be called something like "DefaultRandom"?</div><div dir="auto"><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div><div name="messageBodySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif">In regards to the sample() function on collections, I have added this as I do believe this is something users need. The name I gave it was pick() as this reads, “From array, pick 2”.</div></div></blockquote><div dir="auto"><br></div><div dir="auto">The name "sample" has been used to good effect in other languages, has a well understood meaning in statistics, and is consistent with Swift language guidelines. The operation here is a sampling, and per Swift guidelines the name must be a noun: therefore, 'sample' is fitting. "Pick" does not intrinsically suggest randomness, whereas sample does, and your proposed reading uses it as a verb, whereas Swift guidelines tell us it must be a noun. I would advocate strongly for using well-established terminology and sticking with "sample."</div><div dir="auto"><br></div><div dir="auto"><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div><div name="messageBodySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"></div></div></blockquote><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div><div name="messageReplySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif">On Nov 17, 2017, 8:32 PM -0600, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>>, wrote:<br></div></div><div><div name="messageReplySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,73,94)"><div>On Fri, Nov 17, 2017 at 7:11 PM, Brent Royal-Gordon<span class="m_-7020328610336886033Apple-converted-space"> </span><span><<a href="mailto:brent@architechies.com" target="_blank">brent@<wbr>architechies.com</a>></span><span class="m_-7020328610336886033Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(46,204,113)"><div style="word-wrap:break-word"><div><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(155,89,182)"><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><div>On Nov 17, 2017, at 3:09 PM, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-interchange-newline"></div><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><div><div 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">But actually, Int.random followed by % is the much bigger issue and a very good cautionary tale for why T.random is not a good idea. Swift should help users do the correct thing, and getting a random value across the full domain and computing an integer modulus is never the correct thing to do because of modulo bias, yet it's a very common error to make. We are much better off eliminating this API and encouraging use of the correct API, thereby reducing the likelihood of users making this category of error.<br></div><div 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"></div></div></div></blockquote><div><br></div><div>Amen.</div><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(155,89,182)"><div><div 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">If (and I agree with this) the range-based notation is less intuitive (0..<10.random is certainly less discoverable than Int.random), then we ought to offer an API in the form of `Int.random(in:)` but not `Int.random`. This does not preclude a `Collection.random` API as Alejandro proposes, of course, and that has independent value as Gwendal says.</div></div></blockquote></div></div><div><br></div><div>If we're not happy with the range syntax, maybe we should put `random(in:)`-style methods on the RNG protocol as extension methods instead. Then there's a nice, uniform style:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = rng.random(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = rng.random(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = rng.random(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = rng.random(in: 0.0...1.0)
<span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">
// Special FloatingPoint overload</span></span></div><div><br></div><div>The only issue is that this makes the default RNG's name really important. Something like:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">DefaultRandom.shared.random(in<wbr>: 1...6)</span></div><div><br></div><div>Will be a bit of a pain for users.</div></div></blockquote><div><br></div><div>I did in fact implement this style of RNG in NumericAnnex, but I'm not satisfied with the design myself. Not only is it a bit of an ergonomic thorn, there's also another drawback that actually has weighty implications:</div><div><br></div><div>Users aren't conditioned to reuse RNG instances. Perhaps, it is because it can "feel" wrong that multiple random instances should come from the *same* RNG. Instead, it "feels" more right to initialize a new RNG for every random number. After all, if one RNG is random, two must be randomer! This error is seen with some frequency in other languages that adopt this design, and they sometimes resort to educating users through documentation that isn't consistently heeded.</div><div><br></div><div>Of course, you and I both know that this is not ideal for performance. Moreover, for a number of PRNG algorithms, the first few hundred or thousand iterations can be more predictable than later iterations. (Some algorithms discard the first n iterations, but whether that's adequate depends on the quality of the seed, IIUC.) Both of these issues don't apply specifically to a default RNG type that cannot be initialized and always uses entropy from the global pool, but that's not enough to vindicate the design, IMO. By emphasizing *which* RNG instance is being used for random number generation, the design encourages non-reuse of non-default RNGs, which is precisely where this common error matters for performance (and maybe security).</div><div><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(46,204,113)"><div style="word-wrap:break-word"><div>Maybe we call the default RNG instance `random`, and then give the `random(in:)` methods another name, like `choose(in:)`?</div><div><br></div><div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = random.choose(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = random.choose(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = random.choose(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = random.choose(in: 0.0...1.0)</span></div></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap"></span></div><div><div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = rng.choose(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = rng.choose(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = rng.choose(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = rng.choose(in: 0.0...1.0)</span></div></div></div><div><br></div><div>This would allow us to keep the default RNG's type private and expose it only as an existential—which means more code will treat RNGs as black boxes, and people will extend the RNG protocol instead of the default RNG struct—while also putting our default random number generator under the name `random`, which is probably where people will look for such a thing.</div></div></blockquote><div><br></div><div>I've said this already in my feedback, but it can get lost in the long chain of replies, so I'll repeat myself here because it's relevant to the discussion. I think one of the major difficulties of discussing the proposed design is that Alejandro has chosen to use a property called "random" to name multiple distinct functions which have distinct names in other languages. In fact, almost every method or function is being named "random." We are tripping over ourselves and muddling our thinking (or at least, I find myself doing so) because different things have the exact same name, and if I'm having this trouble after deep study of the design, I think it's a good sign that this is going to be greatly confusing to users generally.</div><div><br></div><div>First, there's Alejandro's _static random_, which he proposes to return an instance of type T given a type T. In Python, this is named `randint(a, b)` for integers, and `random` (between 0 and 1) or `uniform(a, b)` for floating-type types. The distinct names reflect the fact that `randint` and `uniform` are mathematically quite different (one samples a *discrete* uniform distribution and the other a *continuous* uniform distribution), and I'm not aware of non-numeric types offering a similar API in Python. These distinct names accurately reflect critiques from others on this list that the proposed protocol `Randomizable` lumps together types that don't share any common semantics for their _static random_ method, and that the protocol is of questionable utility because types in general do not share sufficient semantics such that one can do interesting work in generic code with such a protocol.</div><div><br></div><div>Then there's Alejandro's _instance random_, which he proposes to return an element of type T given a instance of a collection of type T. In Python, this is named "choice(seq)" (for one element, or else throws an error) and "sample(seq, k)" (for up to k elements). As I noted, Alejandro was right to draw an analogy between _instance random_ and other instance properties of a Collection such as `first` and `last`. In fact, the behavior of Python's "choice" (if modified to return an Optional) and "sample", as a pair, would fit in very well next to Swift's existing pairs of `first` and `prefix(k)` and `last` and `suffix(k)`. We could trivially Swiftify the names here; for example:</div><div><br></div><div>```</div><div>[1, 2, 3].first</div><div>[1, 2, 3].any // or `choice`, or `some`, or...</div><div>[1, 2, 3].last</div><div><br></div><div>[1, 2, 3].prefix(2)</div><div>[1, 2, 3].sample(2)</div><div>[1, 2, 3].suffix(2)</div><div>```</div><div><br></div><div>I'm going to advocate again for _not_ naming all of these distinct things "random". Even in conducting this discussion, it's so hard to keep track of what particular function a person is giving feedback about.</div><div><br></div><div><br></div></div></div></div></blockquote></div></div><div><div name="messageReplySection" style="font-size:14px;font-family:-apple-system,BlinkMacSystemFont,sans-serif"><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,73,94)">______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br></blockquote></div></div></blockquote></div></div></blockquote><br>On Nov 17, 2017, 8:32 PM -0600, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>>, wrote:<br><br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,152,219)"><div>On Fri, Nov 17, 2017 at 7:11 PM, Brent Royal-Gordon<span class="m_-7020328610336886033Apple-converted-space"> </span><span><<a href="mailto:brent@architechies.com" target="_blank">brent@<wbr>architechies.com</a>></span><span class="m_-7020328610336886033Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div style="word-wrap:break-word"><div><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,73,94)"><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><div>On Nov 17, 2017, at 3:09 PM, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-interchange-newline"></div><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><div><div 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">But actually, Int.random followed by % is the much bigger issue and a very good cautionary tale for why T.random is not a good idea. Swift should help users do the correct thing, and getting a random value across the full domain and computing an integer modulus is never the correct thing to do because of modulo bias, yet it's a very common error to make. We are much better off eliminating this API and encouraging use of the correct API, thereby reducing the likelihood of users making this category of error.<br></div><div 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"></div></div></div></blockquote><div><br></div><div>Amen.</div><div class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-"><br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,73,94)"><div><div 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">If (and I agree with this) the range-based notation is less intuitive (0..<10.random is certainly less discoverable than Int.random), then we ought to offer an API in the form of `Int.random(in:)` but not `Int.random`. This does not preclude a `Collection.random` API as Alejandro proposes, of course, and that has independent value as Gwendal says.</div></div></blockquote></div></div><div><br></div><div>If we're not happy with the range syntax, maybe we should put `random(in:)`-style methods on the RNG protocol as extension methods instead. Then there's a nice, uniform style:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = rng.random(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = rng.random(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = rng.random(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = rng.random(in: 0.0...1.0)
<span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">
// Special FloatingPoint overload</span></span></div><div><br></div><div>The only issue is that this makes the default RNG's name really important. Something like:</div><div><br></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">DefaultRandom.shared.random(in<wbr>: 1...6)</span></div><div><br></div><div>Will be a bit of a pain for users.</div></div></blockquote><div><br></div><div>I did in fact implement this style of RNG in NumericAnnex, but I'm not satisfied with the design myself. Not only is it a bit of an ergonomic thorn, there's also another drawback that actually has weighty implications:</div><div><br></div><div>Users aren't conditioned to reuse RNG instances. Perhaps, it is because it can "feel" wrong that multiple random instances should come from the *same* RNG. Instead, it "feels" more right to initialize a new RNG for every random number. After all, if one RNG is random, two must be randomer! This error is seen with some frequency in other languages that adopt this design, and they sometimes resort to educating users through documentation that isn't consistently heeded.</div><div><br></div><div>Of course, you and I both know that this is not ideal for performance. Moreover, for a number of PRNG algorithms, the first few hundred or thousand iterations can be more predictable than later iterations. (Some algorithms discard the first n iterations, but whether that's adequate depends on the quality of the seed, IIUC.) Both of these issues don't apply specifically to a default RNG type that cannot be initialized and always uses entropy from the global pool, but that's not enough to vindicate the design, IMO. By emphasizing *which* RNG instance is being used for random number generation, the design encourages non-reuse of non-default RNGs, which is precisely where this common error matters for performance (and maybe security).</div><div><br></div><blockquote class="gmail_quote" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(211,84,0)"><div style="word-wrap:break-word"><div>Maybe we call the default RNG instance `random`, and then give the `random(in:)` methods another name, like `choose(in:)`?</div><div><br></div><div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = random.choose(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = random.choose(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = random.choose(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = random.choose(in: 0.0...1.0)</span></div></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap"></span></div><div><div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let diceRoll = rng.choose(in: 1...6)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let card = rng.choose(in: deck)</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let isHeads = rng.choose(in: [true, false])</span></div><div><span class="m_-7020328610336886033m_1846945263657774348m_3916470094862887079m_-4753839258241421420gmail-m_1491587401867435223Apple-tab-span" style="white-space:pre-wrap">let probability = rng.choose(in: 0.0...1.0)</span></div></div></div><div><br></div><div>This would allow us to keep the default RNG's type private and expose it only as an existential—which means more code will treat RNGs as black boxes, and people will extend the RNG protocol instead of the default RNG struct—while also putting our default random number generator under the name `random`, which is probably where people will look for such a thing.</div></div></blockquote><div><br></div><div>I've said this already in my feedback, but it can get lost in the long chain of replies, so I'll repeat myself here because it's relevant to the discussion. I think one of the major difficulties of discussing the proposed design is that Alejandro has chosen to use a property called "random" to name multiple distinct functions which have distinct names in other languages. In fact, almost every method or function is being named "random." We are tripping over ourselves and muddling our thinking (or at least, I find myself doing so) because different things have the exact same name, and if I'm having this trouble after deep study of the design, I think it's a good sign that this is going to be greatly confusing to users generally.</div><div><br></div><div>First, there's Alejandro's _static random_, which he proposes to return an instance of type T given a type T. In Python, this is named `randint(a, b)` for integers, and `random` (between 0 and 1) or `uniform(a, b)` for floating-type types. The distinct names reflect the fact that `randint` and `uniform` are mathematically quite different (one samples a *discrete* uniform distribution and the other a *continuous* uniform distribution), and I'm not aware of non-numeric types offering a similar API in Python. These distinct names accurately reflect critiques from others on this list that the proposed protocol `Randomizable` lumps together types that don't share any common semantics for their _static random_ method, and that the protocol is of questionable utility because types in general do not share sufficient semantics such that one can do interesting work in generic code with such a protocol.</div><div><br></div><div>Then there's Alejandro's _instance random_, which he proposes to return an element of type T given a instance of a collection of type T. In Python, this is named "choice(seq)" (for one element, or else throws an error) and "sample(seq, k)" (for up to k elements). As I noted, Alejandro was right to draw an analogy between _instance random_ and other instance properties of a Collection such as `first` and `last`. In fact, the behavior of Python's "choice" (if modified to return an Optional) and "sample", as a pair, would fit in very well next to Swift's existing pairs of `first` and `prefix(k)` and `last` and `suffix(k)`. We could trivially Swiftify the names here; for example:</div><div><br></div><div>```</div><div>[1, 2, 3].first</div><div>[1, 2, 3].any // or `choice`, or `some`, or...</div><div>[1, 2, 3].last</div><div><br></div><div>[1, 2, 3].prefix(2)</div><div>[1, 2, 3].sample(2)</div><div>[1, 2, 3].suffix(2)</div><div>```</div><div><br></div><div>I'm going to advocate again for _not_ naming all of these distinct things "random". Even in conducting this discussion, it's so hard to keep track of what particular function a person is giving feedback about.</div><div><br></div><div><br></div></div></div></div></blockquote><br><blockquote type="cite" style="margin:5px;padding-left:10px;border-left-width:thin;border-left-style:solid;border-left-color:rgb(52,152,219)">______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br></blockquote></div></div></div></div></blockquote></div><br></div></div></blockquote></div></div></div></blockquote></div><br></div></div>______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br></div></blockquote></div><br></div></div>______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br></div></blockquote></div></div></div><br></div></div><br>______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a></blockquote></div></div></div></div></blockquote></div><br></div></blockquote></div><br></div></div>