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
`[0, 2, 3].random` selects a single element from the given collection
`Int.random(in: 0…8)` selects a single element from the given range
`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)
So to me these are all doing the same operation, just with different types of 
inputs

> 2017/11/24 20:07、Alejandro Alonso <aalonso...@outlook.com>のメール:
> 
> 
> - Alejandro
> 
> ---------- Forwarded message ----------
> From: Xiaodi Wu <xiaodi...@gmail.com>
> Date: Nov 24, 2017, 3:05 PM -0600
> To: Alejandro Alonso <aalonso...@outlook.com>
> Cc: Brent Royal-Gordon <br...@architechies.com>, Steve Canon via 
> swift-evolution <swift-evolution@swift.org>
> Subject: Re: [swift-evolution] [Proposal] Random Unification
> 
>> On Fri, Nov 24, 2017 at 2:55 PM, Alejandro Alonso <aalonso...@outlook.com 
>> <mailto:aalonso...@outlook.com>> wrote:
>> 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.
>> 
>> 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.
>> 
>> 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"
>> 
>> "Sampling" is fine.
>> 
>> 
>> On Nov 23, 2017, 12:54 AM -0600, Xiaodi Wu , wrote:
>>> On Wed, Nov 22, 2017 at 23:01 Alejandro Alonso <aalonso...@outlook.com 
>>> <mailto:aalonso...@outlook.com>> wrote:
>>> 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).
>>> 
>>> 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"?
>>> 
>>> 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”.
>>> 
>>> 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."
>>> 
>>> 
>>> On Nov 17, 2017, 8:32 PM -0600, Xiaodi Wu via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>, wrote:
>>>> On Fri, Nov 17, 2017 at 7:11 PM, Brent Royal-Gordon 
>>>> <br...@architechies.com <mailto:br...@architechies.com>> wrote:
>>>>> On Nov 17, 2017, at 3:09 PM, Xiaodi Wu via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>> 
>>>>> 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.
>>>> 
>>>> Amen.
>>>> 
>>>>> 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.
>>>> 
>>>> 
>>>> 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:
>>>> 
>>>> let diceRoll = rng.random(in: 1...6)
>>>> let card = rng.random(in: deck)
>>>> let isHeads = rng.random(in: [true, false])
>>>> let probability = rng.random(in: 0.0...1.0)
>>>> 
>>>> // Special FloatingPoint overload
>>>> 
>>>> The only issue is that this makes the default RNG's name really important. 
>>>> Something like:
>>>> 
>>>> DefaultRandom.shared.random(in: 1...6)
>>>> 
>>>> Will be a bit of a pain for users.
>>>> 
>>>> 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:
>>>> 
>>>> 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.
>>>> 
>>>> 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).
>>>> 
>>>> Maybe we call the default RNG instance `random`, and then give the 
>>>> `random(in:)` methods another name, like `choose(in:)`?
>>>> 
>>>> let diceRoll = random.choose(in: 1...6)
>>>> let card = random.choose(in: deck)
>>>> let isHeads = random.choose(in: [true, false])
>>>> let probability = random.choose(in: 0.0...1.0)
>>>> let diceRoll = rng.choose(in: 1...6)
>>>> let card = rng.choose(in: deck)
>>>> let isHeads = rng.choose(in: [true, false])
>>>> let probability = rng.choose(in: 0.0...1.0)
>>>> 
>>>> 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.
>>>> 
>>>> 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.
>>>> 
>>>> 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.
>>>> 
>>>> 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:
>>>> 
>>>> ```
>>>> [1, 2, 3].first
>>>> [1, 2, 3].any // or `choice`, or `some`, or...
>>>> [1, 2, 3].last
>>>> 
>>>> [1, 2, 3].prefix(2)
>>>> [1, 2, 3].sample(2)
>>>> [1, 2, 3].suffix(2)
>>>> ```
>>>> 
>>>> 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.
>>>> 
>>>> 
>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> On Nov 17, 2017, 8:32 PM -0600, Xiaodi Wu via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>, wrote:
>> 
>>> On Fri, Nov 17, 2017 at 7:11 PM, Brent Royal-Gordon <br...@architechies.com 
>>> <mailto:br...@architechies.com>> wrote:
>>>> On Nov 17, 2017, at 3:09 PM, Xiaodi Wu via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> 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.
>>> 
>>> Amen.
>>> 
>>>> 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.
>>> 
>>> 
>>> 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:
>>> 
>>> let diceRoll = rng.random(in: 1...6)
>>> let card = rng.random(in: deck)
>>> let isHeads = rng.random(in: [true, false])
>>> let probability = rng.random(in: 0.0...1.0)
>>> 
>>> // Special FloatingPoint overload
>>> 
>>> The only issue is that this makes the default RNG's name really important. 
>>> Something like:
>>> 
>>> DefaultRandom.shared.random(in: 1...6)
>>> 
>>> Will be a bit of a pain for users.
>>> 
>>> 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:
>>> 
>>> 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.
>>> 
>>> 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).
>>> 
>>> Maybe we call the default RNG instance `random`, and then give the 
>>> `random(in:)` methods another name, like `choose(in:)`?
>>> 
>>> let diceRoll = random.choose(in: 1...6)
>>> let card = random.choose(in: deck)
>>> let isHeads = random.choose(in: [true, false])
>>> let probability = random.choose(in: 0.0...1.0)
>>> let diceRoll = rng.choose(in: 1...6)
>>> let card = rng.choose(in: deck)
>>> let isHeads = rng.choose(in: [true, false])
>>> let probability = rng.choose(in: 0.0...1.0)
>>> 
>>> 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.
>>> 
>>> 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.
>>> 
>>> 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.
>>> 
>>> 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:
>>> 
>>> ```
>>> [1, 2, 3].first
>>> [1, 2, 3].any // or `choice`, or `some`, or...
>>> [1, 2, 3].last
>>> 
>>> [1, 2, 3].prefix(2)
>>> [1, 2, 3].sample(2)
>>> [1, 2, 3].suffix(2)
>>> ```
>>> 
>>> 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.
>>> 
>>> 
>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to