Skip to content

Commit 3c3c75b

Browse files
committed
Make .random a function
Fix last few .random
1 parent 3c5bb64 commit 3c3c75b

File tree

1 file changed

+25
-25
lines changed

1 file changed

+25
-25
lines changed

proposals/nnnn-random-unification.md

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Next, we will make `FixedWidthInteger`, `BinaryFloatingPoint`, and `Bool` confor
112112
// The following utilizes each integer's full range extent (T.min ... T.max)
113113

114114
// Utilizes the standard library's default random (alias to Int.random(using: Random.default))
115-
let randomInt = Int.random
115+
let randomInt = Int.random()
116116
let randomUInt = UInt.random(using: myCustomRandomNumberGenerator)
117117

118118
// The following is extended for types that conform to both Randomizable and Strideable
@@ -126,7 +126,7 @@ let randomUIntFrom10Through100 = UInt.random(in: 10 ... 100, using: myCustomRand
126126
// For floating points, the range is set to 0 to 1 exclusive
127127

128128
// Utilizes the standard library's default random (alias to Float.random(using: Random.default))
129-
let randomFloat = Float.random
129+
let randomFloat = Float.random()
130130
let randomDouble = Double.random(using: myCustomRandomNumberGenerator)
131131

132132
// The following is extended for types that conform to both Randomizable and BinaryFloatingPoint
@@ -138,18 +138,18 @@ let randomDoubleFrom0Through5 = Double.random(in: 0.0 ... 5.0, using: myCustomRa
138138
`Bool` example:
139139
```swift
140140
// Utilizes the standard library's default random (alias to Bool.random(using: Random.default))
141-
let randomBool1 = Bool.random
141+
let randomBool1 = Bool.random()
142142
let randomBool2 = Bool.random(using: myCustomRandomNumberGenerator)
143143
```
144144

145-
For `Collection` we add the random property and method onto `Collection` itself, then add default implementation along with it.
145+
For `Collection` we add the random method onto `Collection` itself, then add default implementation along with it.
146146

147147
`Collection` example:
148148
```swift
149149
let greetings = ["hey", "hi", "hello", "hola"]
150150

151151
// Utilizes the standard library's default random (alias to greetings.random(using: Random.default))
152-
print(greetings.random as Any) // This returns an Optional
152+
print(greetings.random() as Any) // This returns an Optional
153153
print(greetings.random(using: myCustomRandomNumberGenerator) as Any) // This returns an Optional
154154
```
155155

@@ -160,7 +160,7 @@ For `Range` and `ClosedRange` we extend these types and add this functionality i
160160
let numbers = 0.0 ..< 5.0
161161

162162
// Utilizes the standard library's default random (alias to numbers.random(using: Random.default))
163-
print(numbers.random as Any) // This returns an Optional
163+
print(numbers.random() as Any) // This returns an Optional
164164
print(numbers.random(using: myCustomRandomNumberGenerator) as Any) // This returns an Optional
165165
```
166166

@@ -169,7 +169,7 @@ print(numbers.random(using: myCustomRandomNumberGenerator) as Any) // This retur
169169
let numbers = 0.0 ... 5.0
170170

171171
// Utilizes the standard library's default random (alias to numbers.random(using: Random.default))
172-
print(numbers.random as Any) // This returns an Optional
172+
print(numbers.random() as Any) // This returns an Optional
173173
print(numbers.random(using: myCustomRandomNumberGenerator) as Any) // This returns an Optional
174174
```
175175

@@ -231,7 +231,7 @@ public struct Random : RandomNumberGenerator {
231231
public protocol Collection {
232232
// Returns a random element from the collection (uses Random.default)
233233
// Can return an Optional if isEmpty is true
234-
var random: Element? { get }
234+
func random() -> Element?
235235

236236
// Returns a random element from the collection (uses the rng provided)
237237
// Can return an Optional if isEmpty is true
@@ -240,7 +240,7 @@ public protocol Collection {
240240

241241
extension Collection {
242242
// Default implementation
243-
public var random: Element? {
243+
public func random() -> Element? {
244244
return self.random(using: Random.default)
245245
}
246246

@@ -253,7 +253,7 @@ extension Collection {
253253
// this to make sure users can do things like (5.0 ..< 12.0).random
254254
extension Range where Bound : BinaryFloatingPoint {
255255
// Returns a random BinaryFloatingPoint within lowerBound and upperBound (uses Random.default)
256-
public var random: Bound? {
256+
public func random() -> Bound? {
257257
return self.random(using: Random.default)
258258
}
259259

@@ -266,7 +266,7 @@ extension Range where Bound : BinaryFloatingPoint {
266266
// this to make sure users can do things like (5.0 ... 12.0).random
267267
extension ClosedRange where Bound : BinaryFloatingPoint {
268268
// Returns a random BinaryFloatingPoint within lowerBound and upperBound (uses Random.default)
269-
public var random: Bound? {
269+
public func random() -> Bound? {
270270
return self.random(using: Random.default)
271271
}
272272

@@ -281,7 +281,7 @@ public protocol Randomizable {
281281

282282
extension Randomizable {
283283
// Enables the shortcut for uses like Int.random
284-
public static var random: Self {
284+
public static func random() -> Self {
285285
return self.random(using: Random.default)
286286
}
287287
}
@@ -291,14 +291,14 @@ extension Randomizable {
291291
// this returns a non-optional. Ranges get the benefit of using random, but this is the preferred
292292
// method as it provides a cleaner API to users and clearly expresses the operation.
293293
// It is worth noting that any empty range entered here will abort the program.
294-
// We do this to preserve a clean API which may help steer people from T.random % num (where T: BinaryInteger)
294+
// We do this to preserve a clean API which may help steer people from T.random() % num (where T: BinaryInteger)
295295
// For those that are that unsure whether or not their range is empty or not,
296296
// they can simply call random from the range itself to produce an Optional, or if/guard check
297297
// whether or not the range is empty beforehand, then use these functions.
298298
extension Randomizable where Self: BinaryFloatingPoint {
299299
// Utilizes Random.default
300300
public static func random(in range: Range<Self>) -> Self {
301-
return range.random!
301+
return range.random()!
302302
}
303303

304304
// Utilizes the rng provided
@@ -311,7 +311,7 @@ extension Randomizable where Self: BinaryFloatingPoint {
311311

312312
// Utilizes Random.default
313313
public static func random(in range: ClosedRange<Self>) -> Self {
314-
return range.random!
314+
return range.random()!
315315
}
316316

317317
// Utilizes the rng provided
@@ -328,14 +328,14 @@ extension Randomizable where Self: BinaryFloatingPoint {
328328
// this returns a non-optional. Ranges get the benefit of using random, but this is the preferred
329329
// method as it provides a cleaner API to users and clearly expresses the operation.
330330
// It is worth noting that any empty range entered here will abort the program.
331-
// We do this to preserve a clean API which may help steer people from T.random % num (where T: BinaryInteger)
331+
// We do this to preserve a clean API which may help steer people from T.random() % num (where T: BinaryInteger)
332332
// For those that are that unsure whether or not their range is empty or not,
333333
// they can simply call random from the range itself to produce an Optional, or if/guard check
334334
// whether or not the range is empty beforehand, then use these functions.
335335
extension Randomizable where Self: Strideable, Self.Stride: SignedInteger {
336336
// Utilizes Random.default
337337
public static func random(in range: CountableRange<Self>) -> Self {
338-
return range.random!
338+
return range.random()!
339339
}
340340

341341
// Utilizes the rng provided
@@ -348,7 +348,7 @@ extension Randomizable where Self: Strideable, Self.Stride: SignedInteger {
348348

349349
// Utilizes Random.default
350350
public static func random(in range: CountableClosedRange<Self>) -> Self {
351-
return range.random!
351+
return range.random()!
352352
}
353353

354354
// Utilizes the rng provided
@@ -428,7 +428,7 @@ I spent a lot of time deciding what to do if it failed. Ultimately it came down
428428
In a world where this did return an error to Swift, it would require types that implement `Randomizable` to return Optionals as well.
429429

430430
```swift
431-
let random = Int.random!
431+
let random = Int.random()!
432432
```
433433

434434
"I just want a random number, what is this ! the compiler is telling me to add?"
@@ -451,16 +451,16 @@ Swift is a safe language which means that it shouldn't be encouraging non-experi
451451

452452
It has been discussed to give this a name such as `RNG`. I went with `RandomNumberGenerator` because it is concise, whereas `RNG` has a level of obscurity to those who don't know the acronym.
453453

454-
### Rename Collection.random to Collection.randomElement
454+
### Rename Collection.random() to Collection.randomElement()
455455

456-
I chose `.random` over `.randomElement` here because `.randomElement` doesn't match with things like `.first` and `.last`. If the naming for those facilities were `.firstElement` and `.lastElement` then I would have chosen `.randomElement`, but to be consistent I chose `.random`.
456+
I chose `.random()` over `.randomElement()` here because `.randomElement()` doesn't match with things like `.first` and `.last`. If the naming for those facilities were `.firstElement` and `.lastElement` then I would have chosen `.randomElement()`, but to be consistent I chose `.random()`.
457457

458-
### Remove T.random
458+
### Remove T.random()
459459

460460
This was a pretty discussed topic that I disagreed with heavily.
461461

462-
`T.random` is **always** followed by modulus, remove this in favor of `T.random(in:)`. The argument here is that introducing `T.random` opens up the error for modulo bias which does not provide uniformity. While I do see the concern here, I don't believe removing `T.random` is the answer.
462+
`T.random()` is **always** followed by modulus, remove this in favor of `T.random(in:)`. The argument here is that introducing `T.random()` opens up the error for modulo bias which does not provide uniformity. While I do see the concern here, I don't believe removing `T.random()` is the answer.
463463

464-
Modulo bias is only a concern to types where they conform to `BinaryInteger`. Types that implement `Randomizable` and not `BinaryInteger` shouldn't have this functionality removed. Not only that, `T.random` is the core purpose of `Randomizable`. Typing `Int.random` in an autocorrect IDE (Xcode) would also reveal `.random(in:)` which should help prevent abuse.
464+
Modulo bias is only a concern to types where they conform to `BinaryInteger`. Types that implement `Randomizable` and not `BinaryInteger` shouldn't have this functionality removed. Not only that, `T.random()` is the core purpose of `Randomizable`. Typing `Int.random()` in an autocorrect IDE (Xcode) would also reveal `.random(in:)` which should help prevent abuse.
465465

466-
A proposed solution to this is to just have users do `Int.random(in: Int.min ... Int.max)`. This doesn't work in the first place because internally collections utilize the `count` property to determine the upperBound, and `count` isn't expressible for this range as it exceeds `Int`'s range. For developers that need this functionality, the solution for them is something like this: `Int(truncatingIfNeeded: Random.default.next(UInt.self))`. 1. This doesn't clearly express the operation used here and 2. Creates another pain point for Swift. As the goal of this proposal is to remove pain points regarding random, removing `T.random` does the oppposite and introduces some pain points.
466+
A proposed solution to this is to just have users do `Int.random(in: Int.min ... Int.max)`. This doesn't work in the first place because internally collections utilize the `count` property to determine the upperBound, and `count` isn't expressible for this range as it exceeds `Int`'s range. For developers that need this functionality, the solution for them is something like this: `Int(truncatingIfNeeded: Random.default.next(UInt.self))`. 1. This doesn't clearly express the operation used here and 2. Creates another pain point for Swift. As the goal of this proposal is to remove pain points regarding random, removing `T.random()` does the oppposite and introduces some pain points.

0 commit comments

Comments
 (0)