Here is my wishlist:
• A protocol which allows random instances of any type which conforms (they would init from some number of random bytes passed to them… or better yet, they would be passed a source which can give them however many bytes of randomness they need)
• A choice between fast and secure randomness (and possibly other implementations)
• The optional ability to seed so that randomness can be reproduced when needed
It would also be nice to be able to constrain the created instances in some way. For scalars like Float and Int, this would mean being able to define a range which the random value falls in. For dimensional constructs (e.g. colors, points, sizes) you want to be able to constrain each axis individually. This is actually the hardest part to get right, especially if you are trying to keep things secure. Even for graphics applications where security isn’t the issue, biases in the randomness added by naive approaches like using % can be apparent to the eye.
I think what I would like to see is a protocol defining a source of randomness, which does that hard part for you (written in mail):
protocol RandomnessSource {
init(seed: UInt64)
func randomBytes(count: Int) -> [UInt64]
//Default Imp of below provided from above
func randomInt(in: ClosedRange<Int>? = nil) -> Int //nil means don’t constrain ( = nil is shorthand for convenience func randomInt() )
func randomUInt(in: ClosedRange<UInt>? = nil) -> UInt
func randomDouble(in: ClosedRange<Double>? = nil) -> Double
func randomBool() -> Bool
}
…and then a protocol where a type can use that source to create random instances of themselves:
protocol Randomizable {
static func random(_ source: RandomnessSource)
static var fastRandom:Self {get} //Uses default “fast” source (default imp provided)
static var secureRandom:Self {get} //Uses default “secure” source (default imp provided)
}
protocol RangeRandomizable: Randomizable {
static func random(_ source: RandomnessSource, in: ClosedRange<Self>?)
static func fastRandom(in: ClosedRange<Self>?) -> Self //Uses default “fast” source (default imp provided)
static func secureRandom(in: ClosedRange<Self>?) -> Self //Uses default “secure” source (default imp provided)
//Also provides default imp for random(_ source: RandomnessSource) {random(source, in: nil)}, etc...
}
Then things like points/sizes can use scalar types as building blocks:
extension CGFloat: RangeRandomizable {
static func random(_ source: RandomnessSource, in:ClosedRange<CGFloat>){
let doubleRange = //Convert range to double
return CGFloat(source.randomDouble(in: doubleRange))
}
}
extension CGSize: Randomizable {
static func random(source: RandomnessSource){
return CGSize(width: CGFloat.random(source), height: CGFloat.random(source))
}
//Can add convenience functions to bound width/height to range/constant
}
What I do behind the scenes in my own protocol is take a dictionary of named constraints (instead of a range) because I need a common interface for all dimensions:
public enum RandomSourceConstraint<T> {
case none
case constant(T)
case min(T)
case max(T)
case range (T,T)
case custom ( (RandomSourceValue)->T )
//More code here...
}
Thanks,
Jon
···
On Sep 8, 2017, at 3:40 PM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:
Here is some Swift 3 code that allows simple repeatable repeatable random sequences by conforming to a protocol:
RandomSource is a Swift 3 collection which allows creation of a random sequence of any type which conforms to its RandomSourceCreatable protocol. · GitHub
I now use a slightly more complicated version of this which allows more complex types (like colors) to be added and constrained in more interesting ways than just from…to (e.g. Colors with a fixed lightness/brightness, but a range in hue). The base is pretty much the same.
I have found that user-facing code often needs the idea of repeatable/re-creatable randomness. I originally created it to create a sketchy version of lines that had random offsets added to points along the line. If the randomness wasn’t reproducible, then the sketchiness of the line would shift around randomly every time there was a change.
The code I have provided above is not useful for any sort of cryptography/security though. There are different reasons for randomness. Maybe that is something we should consider?
Thanks,
Jon
On Sep 8, 2017, at 9:52 AM, Alejandro Alonso via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello swift evolution, I would like to propose a unified approach to `random()` in Swift. I have a simple implementation here https://gist.github.com/Azoy/5d294148c8b97d20b96ee64f434bb4f5\. This implementation is a simple wrapper over existing random functions so existing code bases will not be affected. Also, this approach introduces a new random feature for Linux users that give them access to upper bounds, as well as a lower bound for both Glibc and Darwin users. This change would be implemented within Foundation.
I believe this simple change could have a very positive impact on new developers learning Swift and experienced developers being able to write single random declarations.
I’d like to hear about your ideas on this proposal, or any implementation changes if need be.
- Alejando
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution