Wanted to toy with adding some sugar in Swift3. Basically, I wanted to be able to do something like:
let randomAdjust = (-10...10).random
To do that, I decided I would need to extend ClosedRange
. But then found it would probably be even better for my case, I really just plan on doing Int's for now, to use CountableClosedRange
. My latest of multiple attempts looked like:
extension CountableClosedRange where Bound == Int {
var random:Int {
return Int(arc4random_uniform(UInt32(self.count) + 1)) + self.lowerBound
}
}
But the playground complains:
error: same-type requirement makes generic parameter 'Bound' non-generic
extension CountableClosedRange where Bound == Int {
I don't even know what it's telling me there.
The way this roadblock is commonly encountered is when attempting to extend Array. This is legal:
But this is illegal:
The compiler complains:
The problem is the use of
==
here in combination with Array's parameterized type Element, because Array is a generic struct.One workaround with Array is to rise up the hierarchy of Array's inheritance to reach something that is not a generic struct:
That's legal because Sequence and Iterator are generic protocols.
Another solution, though, is to rise up the hierarchy from the target type, namely Int. If we can find a protocol to which Int conforms, then we can use the
:
operator instead of==
. Well, there is one:That's the real difference between our two attempts to implement
random
on a range. The reason your attempt hits a roadblock and mine doesn't is that you are using==
whereas I am using:
. I can do that because there's a protocol (FloatingPoint) to which Double conforms.But, as you've been told, with luck all this trickery will soon be a thing of the past.
In Swift 4, what you are attempting is now completely supported. Hooray!
Example in Swift docs: https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID553