tymac tymac - 5 months ago 55
Swift Question

Overloads for '...' exist with these result types: ClosedRange<Bound>, CountableClosedRange<Bound>

Legacy Swift 2 code

let gap = CGFloat(randomInRange(StackGapMinWidth...maxGap))
// Missing argument label 'range:' in call


Updated Swift 3 Code - new error presented

let gap = CGFloat(randomInRange(range: StackGapMinWidth...maxGap))
// No '...' candidates produce the expected contextual result type 'Range<Int>'
// Help message: Overloads for '...' exist with these result types: ClosedRange<Bound>, CountableClosedRange<Bound>



Swift.org Migrating to Swift 3 page says:


Range<Bound>
and
ClosedRange<Bound>
now only require
Comparable
for the bound. This allows you to create a
Range<String>
.
Range
and
ClosedRange
can’t be iterated over (they are not collections anymore), since a value that is merely
Comparable
cannot be incremented.
CountableRange
and
CountableClosedRange
require
Strideable
from their bound and they conform to
Collection
so that you can iterate over them.

Does this means I'm supposed to use
CountableRange<Int>
with
Strideable
?

Answer

As of Swift 3, ..< and ... produce different kinds of ranges:

  • ..< produces a Range (or CountableRange, depending on the underlying type) which describes a half-open range that does not include the upper bound.
  • ... produces a ClosedRange (or CountableClosedRange) which describes a closed range that includes the upper bound.

If the randomInRange() calculates a random number in the given range, including the upper bound, then it should be defined as

func randomInRange(range: ClosedRange<Int>) -> Int {
    // ...
}

and you can call it as

let lo = 1
let hi = 10
let r = randomInRange(range: lo ... hi)
Comments