I’m working with Swift and encountered an issue when using the contains method on an array. The following code works fine:
let result = ["hello", "world"].contains(Optional("hello")) // ✅ Works fine
However, when I try to use the same contains method with the array declared in a separate constant(or variable), I get a compile-time error:
let stringArray = ["hello", "world"]
let result = stringArray.contains(Optional("hello")) // ❌ Compile-time error
The compiler produces the following error message:
Cannot convert value of type 'Optional<String>' to expected argument type 'String'
Both examples seem conceptually similar, but the second one causes a compile-time error, while the first one works fine.
This confuses me because I know that Swift automatically promotes a non-optional value to an optional when comparing it with an optional value. This means "hello" should be implicitly converted to Optional("hello") for the comparison. (🔗 Reference)
The contains(_:) method is defined as:
func contains(_ element: Self.Element) -> Bool
Internally, it calls contains(where:)
, as seen in the Swift source code:
contains(where:)
takes a closure that applies the ==
operator for comparison.
Since Swift allows comparing String
and String?
directly (String
is implicitly promoted to String?
when compared with an optional), I expected contains(where:)
to work the same way.
contains(_:)
behave differently when used with an explicit array variable rather than a direct array literal? If so, why?I know that there are different ways to resolve this, like using nil coalescing or optional binding, but what I’m really looking for is a detailed explanation of why this issue occurs at the compile-time level.
Can anyone explain the underlying reason for this behavior?
Because Swift uses the whole expression to determine the type of a value. So in the first case with the literal value it finds two types, an array of String and a function on that array that passes an optional String so the the only solution that satisfies both those types is an array of optional String, [String?]
In the second example a variable is declared so this is much more straightforward, the array only contains String objects so the type is [String]