I'd be using ExpressibleByIntegerLiteral as an example but this gotcha applies to other literal types as well. Consider the following example:
struct Foo {
var value: Int
init(_ value: Int) {
self.value = value
print("good old init of mine")
}
}
extension Foo: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
print("init with integerLiteral")
self.value = value
}
}
let variableNotLiteral = 123
var foo1: Foo = 123 // init with integerLiteral
var foo2: Foo = Foo(integerLiteral: 123) // init with integerLiteral
var foo3: Foo = Foo(integerLiteral: variableNotLiteral) // init with integerLiteral
var foo4: Foo = Foo(123) // init with integerLiteral
var foo5: Foo = .init(123) // good old init of mine
var foo6: Foo = Foo(123 as Int) // good old init of mine
var foo7: Foo = Foo(Int(123)) // good old init of mine
var foo8: Foo = Foo(variableNotLiteral) // good old init of mine
Everything here is good and unsurprising except for the foo4 :
- the expected "good old init of mine" initialiser is not called.
- I don't see this behaviour documented in
ExpressibleByIntegerLiteralso I am unaware of it. - There was no ambiguity warning or error during compilation to bring my attention to this issue.
You'd think changing from Foo(123) to .init(123) or vice versa is benign... yet here it's an observable behavioural change. Beware!