Binary == with operands of types Int32 and Int


Found out that following equality testing compiles.

let int32: Int32 = 123456
if int32 == Int.max { }

Should this compile at all? Does this make sense?

Valeriy Van

It uses this operator static func == (lhs: Self, rhs: Other) -> Bool where Other : BinaryInteger


This is a well-defined question to ask. For any two integer types with the same signedness you can transform the smaller type to the larger type and then issue the comparison directly. In this case, you can transform Int32 to Int, as all Int32s can be represented uniquely as a value in Int. The comparison is the equivalent to if Int(int32) == Int.max.

If you have two integer types of different signedness you can apply the same transformation, but in some edge cases you may need to confirm that the signed integer is not negative before applying the transformation into the unsigned type (as not all values of Int64 can be uniquely represented in UInt64).


Shouldn't the same logic apply to +, etc?

Nah. == is commutative. I don't want to have to think about the result type being the one on the left or right foot side.


To expand on Jessy’s response, the way to think about someInt == someInt32 isn’t “the Int32 gets converted to Int because Int is bigger”; it’s “if we converted both to an infinitely-sized (signed) integer type, would they be equal?”


Would it be a problem if the following was allowed in swift?

func foo(_ v: Int) {}

var x: Int  = 123
var y: Int8 = 1
x = x + y
x = y + x
x += y
foo(x + y)
foo(y + x)
let w = x + y // Error, or "choose "the greatest" type (in this case Int)"
let w: Int = y + x // ok

Yes, this kind of one-way widening implicit conversion has long been considered a valid future direction to consider, but to do it well requires some very careful design and implementation (for example, in how the allowed conversions could be expressed by type authors, with the one-way nature of the conversions validated by the compiler).

1 Like

The last one is okay. (intTypeX + intTypeY) as IntTypeZ implies to me that the operation is happening within an IntTypeZ container, i.e. both operands get converted to it beforehand, or something equivalent to that. I wouldn't want it if the result type were not explicit.

To me that implies that the conversion happens after the addition, which doesn't seem as useful for a widening conversion. But maybe that's just my C-addled brain.