<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 30, 2017, at 4:11 PM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" class="">xiaodi.wu@gmail.com</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="">On Thu, Nov 30, 2017 at 5:29 PM, Jonathan Hull<span class="Apple-converted-space"> </span></span><span 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; -webkit-text-stroke-width: 0px;" class=""><<a href="mailto:jhull@gbis.com" target="_blank" class="">jhull@gbis.com</a>></span><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=""><span class="Apple-converted-space"> </span></span><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="">wrote:</span><br 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;" class=""><div class="gmail_extra" 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 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 style="word-wrap: break-word;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 30, 2017, at 2:30 PM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank" class="">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-7020328610336886033Apple-interchange-newline"><div class=""><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;" class="">On Thu, Nov 30, 2017 at 3:58 PM, Dave DeLong via swift-evolution<span class="m_-7020328610336886033Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-<wbr class="">evolution@swift.org</a>></span><span class="m_-7020328610336886033Apple-converted-space"> </span>wrote:<br class=""><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;" class=""><div style="word-wrap: break-word;" class=""><br class=""><div class=""><span class=""><br class=""><blockquote type="cite" class=""><div class="">On Nov 30, 2017, at 2:48 PM, Jonathan Hull via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7020328610336886033m_1846945263657774348Apple-interchange-newline"><div class=""><div style="word-wrap: break-word;" class="">I would personally go with:<div class=""><br class=""></div><div class=""><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space: pre-wrap;">        </span>Int.random //Returns a random Int</div></div></div></blockquote><div class=""><br class=""></div></span><div class="">“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 class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word;" class=""><div class=""><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 class=""><br class=""></div></span><div class="">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 class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word;" class=""><div class=""><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 class=""><br class=""></div></span><div class="">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 class=""> </div><div class="">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;" class=""><div style="word-wrap: break-word;" class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word;" class=""><span class=""><div class=""><br class=""></div><div class="">Then a version of each with a ‘using:’ parameter which takes a generator/source:</div><div class=""><br class=""></div><div class=""><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 class=""><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space: pre-wrap;">        </span>Int.random(in: ClosedRange<Int>, using: RandomSource)</div><div class=""><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space: pre-wrap;">        </span>[0,2,3].randomElement(using: RandomSource)</div><div class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">Honestly, given the current capabilities of Swift what this really calls for is custom initializers/functions for dimensional types:</div><div class=""><br class=""></div><div class=""><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space: pre-wrap;">        </span>UIColor.random //This comes from the protocol</div><div class=""><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 class=""><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 class=""><br class=""></div><div class="">Then you can easily get random colors which look like they belong together:</div><div class=""><span class="m_-7020328610336886033m_1846945263657774348Apple-tab-span" style="white-space: pre-wrap;">        </span></div><div class=""><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 class=""><br class=""></div><div class="">There would probably also be a convenience version taking CGFloats and passing them to the real function as ranges:</div><div class=""><br class=""></div><div class=""><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 class=""><br class=""></div><div class=""><br class=""></div></span><div class="">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 class=""><br class=""></div><div class="">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 class="">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 class=""><br class=""></div><div class="">I have also implemented some version of these APIs, both for Random and RepeatablyRandom sources.</div><div class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">static func random(width widthRange: ClosedRange<CGFloat>, height heightRange: ClosedRange<CGFloat>, using source: RandomSource = .default) -> CGSize {</div><div class=""><span class="m_-7020328610336886033Apple-tab-span" style="white-space: pre-wrap;">        </span>let w = CGFloat.random(in: widthRange, using: source)</div><div class=""><span class="m_-7020328610336886033Apple-tab-span" style="white-space: pre-wrap;">        </span>let h = CGFloat.random(in: heightRange, using: source)</div><div class=""><span class="m_-7020328610336886033Apple-tab-span" style="white-space: pre-wrap;">        </span>return CGSize(width: w, height: h)</div><div class="">}</div><div class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">Why do people want to use a different RNG?</div></div></div></div></blockquote><div><br class=""></div><div>I *need* to be able to insert a repeatably random source, otherwise this whole exercise is useless/detrimental to me. My use case is that I need repeatably random values for various graphics effects, as well as to seed various content sources. If the source isn’t random, then things will change every time the user resizes something on the screen.</div><div><br class=""></div><div>For example, if I want a bezier curve to look hand-drawn, I break it into a number of smaller curves, and then offset the points by a small amount (by generating bounded random CGVectors). When the source is repeatable, this looks awesome. If the source is not repeatable, it will dance around whenever the user moves it. It feels flaky.</div><div><br class=""></div><div>It is much more important when it comes to generated content. There without a repeatable source, the content will change every time the user moves/resizes it (or even reloads the file from a save).</div><div><br class=""></div><div>You will find that there are a number of cases where games need this too...</div><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_extra" 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 class="gmail_quote"><div class=""> 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></div></div></blockquote><div><br class=""></div><div>I’m not following you here.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_extra" 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 class="gmail_quote"><div class="">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></div></div></div></blockquote><br class=""></div><div>I’m still not following. I don’t see why you would want different initialization patterns for different sources. The example I gave was about multi-dimensional structs/classes, so the distributions should be independent based on axis…</div><div><br class=""></div><div>Thanks,</div><div>Jon</div><div><br class=""></div><div><br class=""></div><div><br class=""></div><br class=""></body></html>