SLN SLN - 4 months ago 7
Swift Question

A guess for a mechanism behind Type Inference

I've tried this code in the xCode:

let bigNum = Int8.max + Int("1")!
The compiler infers the variable bigNum of type
Int8
and give me a overflow error.

For
Int8.max + Int("1")!
: the left side of "+" has the type of
Int8
the right side has the type of
Int
. Why the compiler did not infer the bigNum as type of
Int
?

Guess: Swift's compiler always infer the tye by the more narrow/restricted value types, because
Int8
is a more small and narrow type compare to the
Int
, therefore adding an
Int8
and an
Int
number would lead to an
Int8
type inference.

Question: Am I right? or mostly right but not precise. If so, please correct me.

Thanks

Answer

The type inference engine doesn't know the bit-width of the Ints. It doesn't even know that Ints are numbers. The engine doesn't know anything about the "restrictedness" or "narrowness" of how types are implemented. It just knows how types relate to each other as supertypes and subtypes ("ISA" relationships), and tries to solve constraint problems by figuring out what it can plug into the type variables you've provided.

The type inference engine instead is basing its choice on the version of + that is selected. None of the Int-based + functions apply. They're all of the form:

public func +(lhs: Int8, rhs: Int8) -> Int8

And this doesn't have an Int8 on both sides. So it picks the next most specific one it can find:

public func +<T : Strideable>(lhs: T, rhs: T.Stride) -> T

Why this one? An Int8 is a SignedInteger. SignedInteger implements Strideable this way:

public protocol Strideable : Comparable {
    associatedtype Stride : SignedNumber
    public func distance(to other: Self) -> Self.Stride
    public func advanced(by n: Self.Stride) -> Self
}

extension SignedInteger {
    public func distance(to other: Self) -> Int
    public func advanced(by n: Int) -> Self
}

By type-inference we see that Stride is Int. So our function is:

public func +(lhs: Int8, rhs: Int) -> Int8

And that of course overflows at runtime.

BTW, the best way to figure out what function Swift has chosen is to Option-Click the + symbol. It'll tell you what types it's using.