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

Erica Sadun erica at ericasadun.com
Thu Jan 21 15:13:43 CST 2016


I like the idea of distinguishing full argument tuple from its members. 

I dislike $_ because the meaning of _ is more "wildcard ignore" than "wildcard match and represent"
I also dislike $* (product) and $... (because it's just horrible)

I don't mind $$ or $#, and could see adding $$.0 or $#.1 aliases for $0 and $1.

-- E

> On Jan 19, 2016, at 8:20 PM, Paul Cantrell via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 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
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


More information about the swift-evolution mailing list