arraysswiftoption-type

Why does Array's contains(_:) method cause an error when comparing an optional value with a non-optional value in Swift?


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)


What I understand so far:


My Questions:

  1. Why does the first example work, but the second one fails with a compile-time error?
  2. What exactly causes this error in the second case, even though both cases involve comparing an optional value with a non-optional value?
  3. Does 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?


Solution

  • 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]