[swift-users] How to be DRY on ranges and closed ranges?

Hooman Mehr hooman at mac.com
Wed Oct 12 18:21:00 CDT 2016


I recommend having explicit precondition and reducing repetition like this:

import Foundation

func random(from range: CountableRange<Int>) -> Int {
    
    precondition(range.count > 0,
                 "The range can't be empty.")

    return random(from: CountableClosedRange(range))
}

func random(from range: CountableClosedRange<Int>) -> Int {
    
    let lowerBound = range.lowerBound
    let upperBound = range.upperBound
    
    precondition(upperBound - lowerBound < Int(UInt32.max),
                 "The range \(range) is too wide. It shouldn't be wider than \(UInt32.max).")
    
    return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
}

let r1 = random(from: 4 ..< 8)
let r2 = random(from: 6 ... 8)

Once we have the new improved Integer protocols <https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md> in place, you will be able to make it generic to support all integer types. (It is possible now, but too messy to be worth doing.)


> On Oct 12, 2016, at 1:23 PM, Adriano Ferreira via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> 
> Hi there!
> 
> Ole Begeman offers here <https://oleb.net/blog/2016/09/swift-3-ranges/> (take a look at the bottom of the page) an interesting consideration about converting between half-open and closed ranges.
> 
> As of now, it seems the way to go is by overloading…
> 
> 
> import Foundation
> 
> func random(from range: Range<Int>) -> Int {
>     let lowerBound = range.lowerBound
>     let upperBound = range.upperBound
>     
>     return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
> }
> 
> func random(from range: ClosedRange<Int>) -> Int {
>     let lowerBound = range.lowerBound
>     let upperBound = range.upperBound
>     
>     return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
> }
> 
> let r1 = random(from: 4 ..< 8)
> let r2 = random(from: 6 ... 8)
> 
> 
> Cheers,
> 
> — A
> 
>> On Oct 12, 2016, at 6:21 AM, Jean-Denis Muys via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>> 
>> Hi,
>> 
>> I defined this:
>> 
>> func random(from r: Range<Int>) -> Int {
>>     let from = r.lowerBound
>>     let to =  r.upperBound
>>     
>>     let rnd = arc4random_uniform(UInt32(to-from))
>>     return from + Int(rnd)
>> }
>> 
>> so that I can do:
>> 
>> let testRandomValue = random(from: 4..<8)
>> 
>> But this will not let me do:
>> 
>> let otherTestRandomValue = random(from: 4...10)
>> 
>> The error message is a bit cryptic:
>> 
>> “No ‘…’ candidate produce the expected contextual result type ‘Range<Int>’”
>> 
>> What is happening is that 4…10 is not a Range, but a ClosedRange.
>> 
>> Of course I can overload my function above to add a version that takes a ClosedRange.
>> 
>> But this is not very DRY.
>> 
>> What would be a more idiomatic way?
>> 
>> Thanks,
>> 
>> Jean-Denis
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org <mailto:swift-users at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org <mailto:swift-users at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20161012/02537f2f/attachment.html>


More information about the swift-users mailing list