[swift-evolution] [Review] SE-0111: Remove type system significance of function argument labels

Pyry Jahkola pyry.jahkola at iki.fi
Sun Jul 3 15:36:48 CDT 2016

> On 30 Jun 2016, Chris Lattner wrote:
> The review of "SE-0111: Remove type system significance of function argument labels" begins now and runs through July 4. The proposal is available here:
> 	https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md <https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md>
> What is your evaluation of the proposal?

+1. With the way the community has settled using argument labels, it seems clear to me that argument labels are part of a function's name and should not affect its type.

What we currently have technically works because the compiler is quite lenient in type conversions between different argument labels. But since there are corner cases lurking where labels in the function type matter (as demonstrated in the proposal), it's best we get rid of them entirely for clarity. As it has been pointed out, the status quo also complicates the overload resolution process and causes confusing error messages when the compiler can't tell if your argument labels are wrong or argument types. We're better without that complexity.

Further, I think removing this oddity could make function application with tuples feasible again (a.k.a the simple form of "tuple splatting" with all arguments in the tuple) by requiring to fully name the function before passing the arguments tuple:

    func doSomething(x: Int, y: Int) -> Bool { return true }
    func doSomething(any: Any) -> Bool { return false } // This can't possibly be considered below.
    let args = (1, 2)
    let named = (x: 1, y: 2)
    let f = doSomething(x:y:)
    f(args)                 // Unambiguous call, if the syntax is made legal (again).
    doSomething(x:y:)(args) // So is this.
    doSomething(args)       // This would still be an error as per SE-0029 <https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md>.
    let tuples = [(1, 2), (3, 4), (5, 6)]
    print(tuples.map(f)) // This would be allowed. (Confusingly it already works despite SE-0029!)

In particular, you couldn't apply a `func` function with a tuple (which was what SE-0029 removed) but you could apply a qualified function reference (SE-0021 <https://github.com/apple/swift-evolution/blob/master/proposals/0021-generalized-naming.md>) as well as a function value (i.e. a named closure) with a tuple, because both of them have set in stone their argument list length before the tuple application and thus suffer from none of the disadvantages listed in the motivation for SE-0029 <https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md#motivation>. That would of course need a separate proposal and can be delayed until Swift 3 has been released.

> Is the problem being addressed significant enough to warrant a change to Swift?


> Does this proposal fit well with the feel and direction of Swift?

I think so.

> If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Well, we've had argument labels in Objective-C but since it's not a strongly typed language I don't think it applies for comparison. However, I naturally feel argument labels in Objective-C as well are part of the function's name rather than its type.

> How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More than a quick reading. I've suggested a similar idea before but didn't motivate it well enough to gain interest back then. Big thanks to Austin for driving it forward this time!

— Pyry

PS. Can anybody explain why the last example in my code above turned out to be allowed even though SE-0029 seems to prohibit it? Here's a more comprehensive test which made me positively surprised that it still worked after SE-0029:

    let f: (Int, Int) -> Int = (+)
    let x = (1, 2)
    let x, y = (3, 4)
    f(1, 2) //=> 3
    // f((1, 2))                          // Does not compile, as expected (SE-0029).
    // f(x)                               // Does not compile, as expected.
    [x, y].map(f) //=> [3, 7]             // Surprisingly compiles, but why?
    let g: ((Int, Int)) -> Int = f        // Huh? So `f` can coerce to a `(tuple) -> Int`?
    g(x) //=> 3                           // So this is what made `map` work above.
    (f as ((Int, Int)) -> Int)(x) //=> 3  // This works too, didn't expect it to.
    [x, y].map(+)  //=> [3, 7]            // Finally, why is this allowed despite SE-0029?

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

More information about the swift-evolution mailing list