Yes, double parenthesis for tuple argument destructuring in closure was discussed in this thread, and I feel it is one of the best options.

But the main question I can't find the clear answer for, what will be with function/closure types in Swift 4. IMO *this* is the main question, not the syntax for tuple destructuring.

Chris, could you please help to clarify the situation with SE-0066 and SE-0110?
In Rationale part of the SE-0110 acceptance message you said:
"... The community and core team agree that this proposal is the right thing to do, and many agree that this could probably have been treated as a bug fix on a previous proposal.
..."
(https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000215.html)

Were you thinking about SE-0110 just as bug fix for SE-0066/SE-0029?

What is your opinion, can we revisit SE-0110 without revisiting SE-0066?

I mean that for me SE-0066 clearly separated *types* for function with one tuple argument and a list of arguments, so (Int,Int)->Void is not the same *type* as ((Int,Int))->Void, and so we just must to assign a right concrete type for closure(depending on its arguments), so we must separate closures that takes one tuple argument and a list of arguments. And SE-0110 just clarifies this.

How do you think, what should be a *type* of these constants after SE-0066?:

let closure1 = {(x: Int, y: Int) in}
let closure2 = {(x: (Int,Int)) in }

print(type(of: closure1)) // ?
print(type(of: closure2)) // ?

For me, based on *SE-0066*, they must be typed as (Int, Int)->Void and ((Int,Int))->Void accordingly, no?

Should type(of: closure1) == type(of: closure2) ?
Can (closure2 is (Int,Int)->Void) == true ?
and (closure1 is ((Int,Int))->Void) == true ?

Having function
func foo(callback: (_ x:(Int,Int))->Void) {..}

, should we be able to just send closure1 to it? I.e.
foo(callback: closure1)  // ?
foo(callback:  {(x: Int, y: Int) in}) // and here?
foo(callback: {x, y in }) // and here?

I even think that we can have implicit conversion between these *types* of closures/funcs (one tuple vs arg list), because this seems to be very handy and used a lot, but IMO after SE-0066 we should have clear and strict type for each kind of func/closure and then, can have clear rule that we can use one *type*, where *another type* is required. Or allow just tuple destructuring by *special* syntax in closure. Again, closure will be of correct *type* but contains tuple destructuring syntax. Or disallow using of different *type* of func/closure when another type is requested.(Exactly this was proposed and accepted by SE-0110, that was inspired by SE-0066)

Having all these said, I can't understand how we can actually revisit SE-0110, because it just clarifies for closures what SE-0066 requires for function types.

Thank you.
Vladimir.

On 04.06.2017 20:16, Chris Lattner via swift-evolution wrote:

On Jun 1, 2017, at 3:06 PM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


On Jun 1, 2017, at 2:39 PM, Pavol Vaskovic <p...@pali.sk <mailto:p...@pali.sk>> 
wrote:

On Thu, Jun 1, 2017 at 8:52 PM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


    I understand that there are developers who dislike SE-0110's impact on 
certain
    kinds of functional programming, but that is a very broad complaint that is
unlikely to reach consensus or acceptance, especially for Swift 4.

The impact of SE-0110 as currently implemented in Swift 4 leads to following migration choice wherever you have a closure that takes tuple argument:
* concise but obfuscate code ($0.1, ...)
* readable but verbose code (requiring a ton of boilerplate: intermediate argument, expand signature to include return type, desctructure tuple on new line using let, add return clause)

Maybe I misunderstood you, but I don't think this is marginal issue affecting only some "developers that dislike the impact on certain kinds of functional programming".

You're misunderstanding me. I have explicitly said, several times, that I agree that the impact on tuple destructuring in closures is a serious regression. There have *also* been objections to losing argument-splat behavior, and while that does negatively affect some functional styles, I think it would be a mistake to try to address that now.

I agree with both points: we need to fix the type checker semantics+performance regression, but I also sympathize with the beauty regression for closures. Here are some the examples Gwendal Roué cited up-thread (just to make the discussion concrete):

Example 1
-        return columns.index { (column, _) in column.lowercased() == 
lowercaseName }
+        return columns.index { $0.0.lowercased() == lowercaseName }

Example 2 :
-            .map { (mappedColumn, baseColumn) -> (Int, String) in
+            .map { (pair) -> (Int, String) in
+                let mappedColumn = pair.key
+                let baseColumn = pair.value

Example 3 :
- .map { (table, columns) in "\(table)(\(columns.sorted().joined(separator: ", ")))" }
+                .map { "\($0.key)(\($0.value.sorted().joined(separator: ", 
")))" }

Example 4 :
- dictionary.first { (column, value) in column.lowercased() == orderedColumn.lowercased() }
+                dictionary.first { $0.key.lowercased() == 
orderedColumn.lowercased() }




One way to split the difference here is to eliminate the splatting behavior, but keep the destructuring (irrefutable pattern matching) behavior as well. In these cases, just require an extra explicit paren for the parameter list. This would change the diff's to:

Example 1
-        return columns.index { (column, _) in column.lowercased() == 
lowercaseName }
+       return columns.index { ((column, _)) in column.lowercased() == 
lowercaseName }

Example 2 :
-            .map { (mappedColumn, baseColumn) -> (Int, String) in
+            .map { ((mappedColumn, baseColumn)) -> (Int, String) in

Example 3 :
- .map { (table, columns) in "\(table)(\(columns.sorted().joined(separator: ", ")))" } + .map { ((table, columns)) in "\(table)(\(columns.sorted().joined(separator: ", ")))" }

Example 4 :
- dictionary.first { (column, value) in column.lowercased() == orderedColumn.lowercased() } + dictionary.first { ((column, value)) in column.lowercased() == orderedColumn.lowercased() }


What do you think? Seems like it would solve the type checker problem, uglify the code a lot less, and make the fixit/migration happily trivial.

-Chris





_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to