[swift-evolution] Proposal: Make $0 always refer to a closure’s first argument

Paul Cantrell cantrell at pobox.com
Tue Jan 19 21:20:24 CST 2016


Surprisingly, this code does not compile:

    func foo(val: Int) { }

    func bar(closure: (Int,Int) -> Void) {
        closure(0, 1)
    }

    bar { foo($0) }       // compiler error
    bar { foo($1) }       // just dandy
    bar { foo($0 + $1) }  // also works

The compiler error is:

    Cannot convert value of type (Int, Int) to expected argument type Int

It appears that the meaning of $0 is overloaded: it can refer either to the tuple of all arguments, or to just the first argument. The presence of another placeholder variable ($1 in the third example) seems to trigger the latter behavior.

This is certainly confusing. I’m posting to the list after receiving two Siesta user questions in the same day that both boil down to this issue.

Even if you do understand the behavior, it’s a real nuisance: it prevents concise implementation of a multi-arg closure which wants to ignore all but its first argument. Instead, such a closure has to drop back to the more verbose syntax:

    bar { a, _ in foo(a) }   // sigh

…or use this legibility-proof workaround:

    bar { foo($0.0) }   // yuck! wat?!

(Note that this problem exists only for the first argument; a closure that wants to ignore all but the second has no such problem.)

This behavior contradicts the Swift documentation, which clearly says that $0 refers to the first argument:

> Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

And:

> A closure may omit names for its parameters. Its parameters are then implicitly named $ followed by their position: $0, $1, $2, and so on.


I can’t find anything in the docs that mentions this “all args tuple” behavior, so perhaps it’s a bug? Let me know if it is, and I’ll just file a bug report for it.

However the “whole tuple” behavior does seem to be intentional, and preserving that while fixing the problem above appears to require a language change. Thus…

Proposal

The implicit closure variable $0 should always refer to the closure’s first argument, and a different implicit name — perhaps $* or $_ or $... — should refer to the all-args tuple.

Thoughts?

Cheers,

Paul

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160119/6431704d/attachment.html>


More information about the swift-evolution mailing list