Swift type inference quirks: closures as parameters

Swift can infer the type of closures when used as parameters. As shown in the official Swift documentation, this means that we don’t need to write code like this:

Instead, we can simply write:

And because single-expression closures can implicitly return the value of the expression, the code above can be shortened to:

Or even more succinctly by using shorthand argument names:

So far so good. However, the documentation leaves out some cases in which Swift fails to infer the closure type properly (as of Xcode 6.0). During the development of Haneke we discovered the two below. You can follow along the code examples with this playground.

Quirk 1: Single-expression closures with unused return value

The first involves single-expression closures. Say we want to set the modification date of a file in background, without much care for errors. Intuitively, we would write something like this:

Unfortunately the above code fails to compile with error Cannot convert the expression's type (dispatch_queue_t!, () -> () -> $T5)' to type 'Bool'.

The reason is that NSFileManager.setAttributes returns a Bool, and because the closure has a single-expression, the Swift compiler mistakenly infers that its return type is Bool.

The workaround? We guide the Swift compiler by ignoring the result value with an underscore:

Quirk 2: Unused parameters in closures

Another quirk involves unused parameters in closures. Consider a function that fetches some data and can succeed or fail.

When writing unit tests for this function we should test both the success case and the failure case. For the failure case, we should fail the test if the success closure gets called. The test could look something like this:

Surprisingly this doesn’t compile. The error message is not very helpful: 'NSData' is not a subtype of '()'.

The problem lies in the unused parameter of the success block. The Swift compiler assumes that the success closure does not have any parameters, and fails to match this with the expected type of the success closure.

What to do? Again the amazing underscore comes to our rescue:

Telling Swift that the success closure has a parameter, even if we ignore it, is enough help to let it infer the type correctly.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">