You are currently viewing 46% of People Think This Swift Code Has Error, Apparently, It Doesn’t!

46% of People Think This Swift Code Has Error, Apparently, It Doesn’t!

A few weeks back, I saw a piece of Swift code being tweeted by @objcio on Twitter. 46% of people think the code has compiler error, and I am one of them. 😅

Here’s the code.

func foo() throws -> Int { 0 }
func foo() throws -> Int? { 1 }

let a = (try? foo())
let b = (try? foo())!

let result = (a == b)

// What’s the value of result? (Swift 5)
// 1. true
// 2. false
// 3. Compiler Error

Here’s the voting result of that tweet.

Twitter voting result
The voting result

Surprisingly, out of 850 people who voted, 46.6% of them think the code snippet above have compiler error. However, that is not the correct answer. The correct answer is…

Drum roll, please!
Drum roll, please!

“true”

This makes me wonder why the majority of people think the code have error and why the answer is “true”.

After spending some time doing research and playing around the code in Xcode playground, here’s my findings.


The False Alarm

Missing Return In a Function

I think most people will think that the following 2 lines of code might get compiler error.

func foo() throws -> Int { 0 }
func foo() throws -> Int? { 1 }

One might think that the return keyword are missing in both functions and the compiler should show error of “Missing return in a function” .

In fact, these 2 lines of code are totally valid due to the inclusion of “Implicit returns from single-expression functions” proposal in Swift 5.1. The proposal suggested that if a closure contains just a single expression, the return keyword can be omitted.

Therefore, the code above is identical to the code below.

func foo() throws -> Int {
    return 0
}

func foo() throws -> Int? {
    return 1
}

Invalid Redeclaration

Another possible reason why people think compiler error will occur is because both functions have the same name foo(). This might cause “Invalid redeclaration of ‘foo()'” error.

However, this is also not true because function overloading is supported by Swift. As long as functions with the same name have different parameters, different argument labels or different return types, no compiler error will trigger.

After knowing what causes the false alarm, next up, let’s get into the interesting part — figuring out why the answer is “true”.


Type Inference in Swift

In order to get the correct answer, we must first know what is type inference in Swift.

Type inference is a Swift language feature where compiler will figure out the appropriate type of your constant or variable if you do not specify it during declaration.

Code snippet below demonstrate type inference in Swift.

let value1 = "some string"
// value1 is inferred to be of type String

let value2 = 123
// value2 is inferred to be of type Int

With that in mind, let’s simplify the tweet’s code into 3 lines so that it is easier to analyse.

func foo() throws -> Int { 0 }
func foo() throws -> Int? { 1 }

let a = (try? foo())

Now, copy the above code into Xcode playground, then change try? to try. You should see that “Ambiguous use of ‘foo()'” compiler error is shown.

Ambiguous use of function in Swift
Ambiguous use of ‘foo()’

The reason why the error happened is because the compiler failed to use type inference to identify the type for a.

When using try (without ? operator) on a throws function, if no error occurred, we will receive the function’s return type. Since foo() have 2 equally possible return types — Int and Int?, the compiler has no way to decide which type a should inferred to.

Now, let’s add back ? to try. You will notice that the compiler error has gone away. This is because when using try? on a throws function, we will always get back an optional type.

The compiler is now able to use type inference and select the closest possible return type for foo(), which is Int?. Therefore, a will have type of Int? and its value will be 1.

Type inference for optional type in Swift
a has value of 1

We can further prove the correctness of our understanding by changing Int? to some other non-optional data type. Type inference should fail this time due to both foo() have 2 equally possible return types. (Note that this time we are using try? but still get the ambiguous error.)

Ambiguous use of function in Swift
Get “Ambiguous use of ‘foo()'” error when change Int? to String

With the tricky part out of the way, we can now continue working towards the final answer.


Getting the Final Answer

To recap, this is the code we are working on.

func foo() throws -> Int { 0 }
func foo() throws -> Int? { 1 }

let a = (try? foo())
let b = (try? foo())!

let result = (a == b)

// What’s the value of result? (Swift 5)
// 1. true
// 2. false
// 3. Compiler Error

We already know that a is optional(1), and b is just force unwrapping of a, which is 1.

(a == b) is equivalent to optional(1) == 1, which is true. Therefore, the value of result is true.


Wrapping Up

I would like to thanks @tammofreese for sharing this interesting piece of code. Anyone who is interested can checkout the original tweet by @objcio.

If you like this article, checkout the following article that showcase another piece of interesting Swift code.


Further Reading


If you like this article, feel free to share it with your friends and leave me a comment. You can follow me on Twitter for more article related to iOS development.

Thanks for reading! 👨🏼‍💻


👋🏻 Hey!

While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.

  • Bartender: Superpower your menu bar and take full control over your menu bar items.
  • CleanShot X: The best screen capture app I’ve ever used.
  • PixelSnap: Measure on-screen elements with ease and precision.
  • iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.