Hello guys I'm new here and right now I'm learning Swift by coding some fancy algorithms, which comes to my mind while reading Apples Swift book.
I was trying to compress (automatically downcast) any IntegerType value. Here is a little snippet of my Code which almost works fine except for one case:
switch signedValue
{
case Int64(Int8.min)...Int64(Int8.max): compressedValue = Int8(signedValue)
case (Int64(Int8.max) + 1)...Int64(UInt8.max): compressedValue = UInt8(signedValue)
case Int64(Int16.min)...Int64(Int16.max): compressedValue = Int16(signedValue)
case (Int64(Int16.max) + 1)...Int64(UInt16.max): compressedValue = UInt16(signedValue)
case Int64(Int32.min)...Int64(Int32.max): compressedValue = Int32(signedValue)
case (Int64(Int32.max) + 1)...Int64(UInt32.max): compressedValue = UInt32(signedValue)
case Int64(Int.min)...Int64(Int.max): compressedValue = Int(signedValue) // range bug #1 - workaround '..<'
default: compressedValue = signedValue
}
Assume signedValue is of Type Int64 and the input value is = 10_000_000_000. This will lead to a runtime error (in Playground):
Execution was interrupted, reason: EXC_BAD_INSTRUCTION ...
Could anyone help me out to understand what exactly is happening here. There is an workaround for this problem. Instead of '...' I could use '..<' but this not how the range should be.
Unlike intervals (which have two flavours, half-open or closed), Range
is only ever half-open. So when you write 1...5
, the ...
function increments the right-hand argument in order to create a half-open range 1..<6
.
The consequence of this is you can’t have a range that spans the entire length of an integer type, since 1...Int.max
will result in an attempt to increment Int.max
, and an overflow error. You get a similar error with let s = "hello"; let r = s.startIndex...s.endIndex
All is not lost, however, since you shouldn’t be using ranges anyway, this is a job for ClosedInterval
. Since the ...
operator is used for both, and defaults to ranges (for overloading precedence reasons) you need to explicitly identify the type:
let i64interval: ClosedInterval = Int64(Int64.min)...Int64(Int64.max)
switch signedValue {
// etc
case i64interval: compressedValue = Int(signedValue)
default: compressedValue = signedValue
}