Proposal: 
https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md

Shortly after SE-0111 was accepted last week, several people newly noticed the 
proposal and started a discussion about how it appears to be a regression for 
closure parameters (e.g. callbacks) that could formerly carry labels, but are 
now not allowed to.  These folks observed that it would be more expressive (and 
consistent with the rest of Swift) to allow parameter labels in function types, 
because the invocation site of a closure “should" be required to provide those 
labels.  The core team has been following the discussion, agrees that this is a 
concern, and wants to update the community with a path forward.

The reality of the situation is that the current implementation of parameter 
labels in function types is inherently broken.  Specifically, as one example, 
there is an implicit conversion from "(a: Int) -> Int” to “(Int) -> Int”.  
However, there is also an implicit conversion from "(Int) -> Int” to “(b : Int) 
-> Int”.  This means that the compiler currently allows converting from “(a: 
Int) -> Int” to “(b: Int) -> Int”, which doesn’t make sense, introduces 
surprising behavior, introduces complexity into the compiler implementation, 
and is generally a problem.  We do have one specific hack to prevent conversion 
of (e.g.) “(a : Int, b : Int) -> Void” to “(b : Int, a : Int) -> Void”, but 
this only triggers in specific cases.  There are other more complex cases as 
well, e.g. when using generics "T<(a : Int)->Int>” cannot be considered 
compatible with "T<(b : Int)->Int>”.

These problems are what initially motivated SE-0111.  However, given the 
feedback, the core team went back to the drawing board to determine whether: a) 
SE-0111 by itself is the right long term answer, b) whether there were 
alternate models that could solve the same problems in a different way, or c) 
whether SE-0111 was the right first step to "ultimate glory" in the field of 
closure parameter labels.  After a long discussion, and many alternatives 
considered, the core team believes in c), that SE-0111 (with a minor 
modification) is the right step for Swift 3, because it paves the way for the 
right model over the long term.

----8<----

The specific revision requested by the core team to SE-0111 is that all 
“cosmetic” labels should be required to include an API name of _.  For example, 
this would not be allowed:

   var op : (lhs : Int, rhs : Int) -> Int

instead, it should be spelled as:

   var op : (_ lhs : Int, _ rhs : Int) -> Int

With this change, we believe that we have paved the way for a purely additive 
proposal (and thus, post-Swift 3) that will restore the expressive capability 
of closures with parameter labels.  

----8<----

Here is a sketch of how that would work, in two steps:


First, we extend declaration names for variables, properties, and parameters to 
allow *parameter names* as part of their declaration name.  For example:

   var op(lhs:,rhs:) : (Int, Int) -> Int    // variable or property.
   x = op(lhs: 1, rhs: 2)       // use of the variable or property.

   // API name of parameter is “opToUse”, internal name is "op(lhs:,rhs:)”.
   func foo(opToUse  op(lhs:,rhs:) : (Int, Int) -> Int) {
     x = op(lhs: 1, rhs: 2)     // use of the parameter
   }
   foo(opToUse: +)             // call of the function

This will restore the ability to express the idea of a closure parameter that 
carries labels as part of its declaration, without requiring parameter labels 
to be part of the type system (allowing, e.g. the operator + to be passed into 
something that requires parameter labels).


Second, extend the rules for function types to allow parameter API labels *if 
and only if* they are used as the type of a declaration that allows parameter 
labels, and interpret them as a sugar form for providing those labels on the 
underlying declaration.  This means that the example above could be spelled as:

   var op : (lhs: Int, rhs: Int) -> Int    // Nice declaration syntax
   x = op(lhs: 1, rhs: 2)                  // Same as above

   // API name of parameter is “opToUse”, internal name is "op(lhs:,rhs:)”.
   func foo(opToUse op : (lhs: Int, rhs: Int) -> Int) {
     x = op(lhs: 1, rhs: 2)     // Same as above.
   }
   foo(opToUse: +)              // Same as above.


These two steps will provide the simple and expressive design approach that we 
have now, without all of the problems that representing parameter labels in the 
type system introduces.  The core team believes that the temporary regression 
in expressiveness is an acceptable loss for Swift 3, particularly given that 
this will have no impact on Cocoa or the standard library.  In the case of 
Cocoa, recall that C and Objective-C don’t have parameter labels on their 
corresponding concepts (Blocks and C function pointers), and the higher order 
functions in the standard library should not require parameter labels either.

-Chris & the Core Team


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to