[swift-evolution] Proposal: Make $0 always refer to a closure’s first argument
Paul Cantrell
cantrell at pobox.com
Wed Jan 27 16:30:00 CST 2016
> On Jan 27, 2016, at 2:20 PM, Dave via swift-evolution <swift-evolution at swift.org> wrote:
>
>> On Jan 27, 2016, at 10:09, Chris Lattner via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>> I’m sorry, I’ve lost context on what the proposal here is. Can you please restate it? To me, it seems most natural that $0 always refer to the first parameter of a closure.
>>
>> -Chris
>
>
> Paul Cantrell’s original post documented behavior which causes $0 to sometimes refer to a tuple of all the arguments instead of the just first argument. John McCall said it was bug, but then Jordan Rose replied and said, ”I wouldn’t go as far as to say it’s a bug. It’s known and occasionally useful for forwarding arguments". My understanding is that everyone agrees on two things: the bug should eventually be fixed, and the bug’s functionality is actually kinda cool (when it’s not biting you) and there should still be a way to invoke it. The debate was over whether to do it now and make $*, $_, $$, $…, or $# (I think that’s all of them) be the “all args” tuple, or whether we should wait fix it until Swift gets “a more complete revision of the varargs system” (which was assumed to be at least Swift 4).
An excellent summary, to which I’d just add: it’s unclear to me whether we need to wait for $* (or whatever the new language feature is) in order to make the “$0 is always the first arg” fix. So there is a third option, which I’d prefer:
1. Declare current “$0 is sometimes a tuple” behavior a bug.
2. Fix it soon so that $0 is always the first arg, maybe even in 2.x.
3. Implement either $* and/or more comprehensive advanced varargs later, probably in 4+.
The case for this approach is:
• the current behavior of $0 is somewhat nonsensical,
• confusion caused by this behavior is common, and
• use of $0 as an all-args tuple is rare and (mostly) easy to work around.
However, this approach hinges on deciding whether the current behavior is a bug or a feature. That's a call I think the core team has to make.
Cheers, P
>
> At least that’s how I understand it. Here’s Paul’s original post:
>
> - Dave Sweeris
>
>> On Jan 19, 2016, at 19:20, Paul Cantrell via swift-evolution <swift-evolution at swift.org <mailto: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 <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> 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/20160127/66b0e8f6/attachment.html>
More information about the swift-evolution
mailing list