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

Hooman Mehr hooman at mac.com
Thu Oct 13 12:52:08 CDT 2016


On more thing:

The result type of my `random()` extension is optional. This might not be ideal. It is not an expected and likely case that `random()` returns nil.  I would personally prefer it to be non-optional and crash if the array is empty, just like it would if you tried to reference a non-existing index in the collection. So, the version I actually prefer is:

extension RandomAccessCollection {
    
    func random() -> Iterator.Element {
        
        precondition(count > 0, "There is no element to random pick.")
        
        let offset = arc4random_uniform(numericCast(count))
        
        let i = index(startIndex, offsetBy: numericCast(offset))
        
        return self[i]
    }
}

> On Oct 13, 2016, at 4:08 AM, Jean-Denis Muys <jdmuys at gmail.com> wrote:
> 
> Thank you for this Hooman, I think this is what I was looking for.
> 
> JD
> 
> On Thu, Oct 13, 2016 at 4:26 AM, Hooman Mehr <hooman at mac.com <mailto:hooman at mac.com>> wrote:
> 
>> On Oct 12, 2016, at 3:21 AM, Jean-Denis Muys via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>> 
>> 
>> But this is not very DRY.
>> 
>> What would be a more idiomatic way?
>> 
> 
> The more idiomatic way is to look at API design in a new way. Note these points:
> 
> 1. `Countable` variant is preferred when you want to deal with integer ranges as it more closely matches the element type.
> 2. Both countable range variants share a common protocol conformance already: `RandomAccessCollection`
> 3. Swift API design prefers member functions to free functions.
> 
> Hence a more idiomatic (Swifty) API would probably be something like this:
> 
> extension RandomAccessCollection {
>     
>     func random() -> Iterator.Element? {
>         
>         guard count > 0 else { return nil }
>         
>         let offset = arc4random_uniform(numericCast(count))
>         
>         let i = index(startIndex, offsetBy: numericCast(offset))
>         
>         return self[i]
>     }
> }
> 
> Using the above, both cases work and there is no repetition:
> 
> (4..<10).random()
> (4...9).random()
> 
> It also makes a lot more possible: 
> 
> let people = ["David", "Chris", "Joe", "Jordan", "Tony"]
> let winner = people.random()
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20161013/38ef8740/attachment.html>


More information about the swift-users mailing list