Hopefully I'm able to provide my justification as best as possible here for the points you mention.
I'm certainly open to the idea (not attached to either spelling). We must also understand that this rename also affects the range based API. (0 ..< 10).randomElement()
. Spellings like this, in my opinion, gives the static T.random(in:)
even more justification as randomElement()
is semantically tied to collections. While Ranges can conditionally conform to become collections, I fear this spelling could hurt the meaning of what it means to get a random number from a range. I agree, this spelling makes a lot of sense for collections, but probably only collections.
I agree with where this line of thinking is coming from, but to me, it seems reasonable that a user should expect that there would a difference in the API when one is a static method vs an instance method.
Again, I don't have feelings towards one spelling or the other. I'm simply providing my rationale for naming the method the name it has now.
In regards to the second point, I think many others have already given great rationale for why this should return an optional. Requiring that this method trap would, in my opinion, cause more harm than good. Literal arrays are the exception in that you know for sure that the array is not empty, but it's very easy to not know what the arrays contents are at runtime. This results in this sort of boilerplate code where you're always checking if the array is empty before calling the random method. I feel Donald summarizes this perfectly.
Not only that rationale, but because there's already a precedent set by other facilities such as min()
and max()
. I keep bringing these back up because I believe a user could ask such questions like, "Why does min()
and max()
return optionals, but random()
doesn't?" I'm a huge fan of consistency, and aligning random()
with these other APIs seems to fit rather nicely.
In the case we do make this trap, is the static methods like Int.random(in:)
still necessary? Yes.
If the naming of this method was randomElement()
, one could make the argument that floating point ranges need to be consistent (huge fan of btw) with ranges that conditionally conform to collection. To me, it doesn't make sense to get a random element from a range that isn't a collection.
(1.0 ..< 10.0).randomElement()
doesn't make sense because there is no element to select from. This justifies the static T.random(in:)
methods which doesn't cause this confusion.
Now, if the naming of this method were named random()
however, in the alternatives considered I wrote, Having a range as the primary spelling makes it fairly simple to get a random number from. Ranges are also very desirable because it doesn't encourage modulo bias.
I still stand by this, but Nate brings up a great point that this design simply doesn't hold for other types that want to incorporate random functionality. Data.random(byteCount:using:)
simply cannot be expressed so simply like a range. It's my mistake to not have mentioned this somewhere in the proposal, but I'm glad we're getting a chance to discuss it now.
I apologize if the proposal doesn't go so in depth in terms of my justification, but like I said, really glad that we get to discuss it now.