Revisiting SE-0110

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.

I've been quietly following the thread. This approach makes sense to me.

···

Sent from my iPad

On Jun 4, 2017, at 12:16 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 1, 2017, at 3:06 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:
On Jun 1, 2017, at 2:39 PM, Pavol Vaskovic <pali@pali.sk> wrote:

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

-Chris

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

One way to split the difference here is to eliminate the splatting behavior, but keep the destructuring (irrefutable pattern matching) behavior as well.

A hearty +1 to this, regardless of the choice of syntax.

P

···

On Jun 4, 2017, at 12:16 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> 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 <pali@pali.sk <mailto:pali@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

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

Thanks for your feedback !

Your solution performs much better, but only to some point: the developers will just add parenthesis until the compiler is happy.

Quoting https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md: <https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md:&gt;

## Motivation

Right now, the following is possible:

let fn1 : (Int, Int) -> Void = { x in
    // The type of x is the tuple (Int, Int).
    // ...
}

let fn2 : (Int, Int) -> Void = { x, y in
    // The type of x is Int, the type of y is Int.
    // ...
}

A variable of function type where there exist n parameters (where n > 1) can be assigned a value (whether it be a named function, a closure literal, or other acceptable value) which either takes in n parameters, or one tuple containing n elements. This seems to be an artifact of the tuple splat behavior removed in SE-0029.

The current behavior violates the principle of least surprise and weakens type safety, and should be changed.

The motivation section is not at all about any "type checker problem". It's about a postulate that has been proven horribly source-breaking, and counter-productive. The type safety argument is moot. The principle of least surprise has been blown away by SE-0110, putting Swift aside from the majority of other languages.

I'm surprised that everybody tries to workaround SE-0110 consequences, admitting that it's relevant, instead of revisiting SE-0110 at its very root.

Gwendal

···

Le 4 juin 2017 à 19:16, Chris Lattner via swift-evolution <swift-evolution@swift.org> a écrit :

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.

+1.

Migration path would be a little less simple if the parameter clause has
type annotations:

- let fn: Int = { (v: String, k: Int) in
+ let fn: Int = { ((v, k): (String, Int)) in

Also, if we accept patterns for closure parameters, we probably don't want
to accept '...' for them.

let fn = { ((_, v): (Int, String)...) -> Int in

···

2017-06-05 2:16 GMT+09:00 Chris Lattner via swift-evolution < swift-evolution@swift.org>:

On Jun 1, 2017, at 3:06 PM, John McCall via swift-evolution < > swift-evolution@swift.org> wrote:
On Jun 1, 2017, at 2:39 PM, Pavol Vaskovic <pali@pali.sk> wrote:
On Thu, Jun 1, 2017 at 8:52 PM, John McCall via swift-evolution < > swift-evolution@swift.org> wrote:

-Chris

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

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 <pali@pali.sk <mailto:pali@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

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

P

···

On Jun 4, 2017, at 12:16 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> 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 <pali@pali.sk <mailto:pali@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

I think the goal of SE 0110 and to a lesser extent 0066 was to disallow this level of intelligence in the compiler.

Interesting.

I happen to think that the goal of SE–110 <https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md&gt; was to make Swift's type system “properly distinguish between functions that take one tuple argument, and functions that take multiple arguments.” Nowhere does that proposal discuss tuple destructuring, and nowhere does it discuss optional parentheses around closure parameter lists.

I might go so far as to say that any commits which *do* affect those things, cannot possibly be correct implementations of the accepted proposal SE–110, because SE–110 did not describe any changes there.

With SE–66 <https://github.com/apple/swift-evolution/blob/master/proposals/0066-standardize-function-type-syntax.md&gt; the case is even more clearcut: that proposal explicitly addresses the question, “Should we require parentheses in closure expression parameter lists?“ and answers it in the negative. The core team’s notes <https://lists.swift.org/pipermail/swift-evolution-announce/2016-May/000138.html&gt; on accepting also specify, “The core team did not feel that this proposal needed to include required parentheses within closures, which have their own fairly specific grammar.”

While technically feasible, it's not desirable to overload parentheses in this manner.

I strongly disagree. Language features are desirable exactly to the extent that they make life better for developers.

Moreover, parentheses are *already* optional in closure parameter lists. Making them mandatory would be source-breaking for no benefit to programmers. Plus having to write double-parentheses in “dict.map{ ((key, value)) in … }” would be needlessly annoying.

This is basically my perspective. There are language features where we've made an intentional decision to require the user to write things in a specific way. Closure parameter lists are not one of them; we've already committed to using a very permissive and flexible grammar. Perhaps that was a mistake, but it's a mistake we've made and cannot reasonably undo, notwithstanding the proposals that are basically "we should ban such-and-such style that, coincidentally, I happen not to use." In the long term, I feel confident that we can deliver an implementation that resolves the multiple-parameter vs. tuple-decomposition ambiguity without making any significant compromises, but I'm not sure whether we can reasonably achieve that in 4.0.

John.

···

On May 30, 2017, at 7:41 AM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:
On Mon, May 29, 2017 at 10:47 PM, Robert Bennett <rltbennett@icloud.com <mailto:rltbennett@icloud.com>> wrote:

In my view there have been far too many calls for making Swift “consistent” in ways that actually make it less enjoyable to use. That is the opposite of “Swifty”, and we should instead prioritize convenience for users above rigid consistency of implementation.

In the case at hand, with Dictionary.map, the vast majority of the time the user doesn’t actually care whether the closure takes two arguments or a single 2-tuple argument. They just know that it takes a key and a value, and they want to be able to write “dict.map{ (key, value) in … }”.

Sure, the closure *does* take a 2-tuple, and it does not take two arguments, but the programmer *using* it shouldn’t have to bother about that distinction most of the time. They just want to assign the key to one identifier and the value to another. If they try to write “key, value” without any parentheses the compiler will complain and they’ll add the parens. But if the compiler demands a *second* set of parentheses, that will just seem ridiculous.

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

Is the version you suggest to add to my list for the Swift syntax currently valid as of SE-0110 in Swift 4?

Yes, just checked on latest dev snapshot of Swift 4.

···

On 02.06.2017 2:34, Tommaso Piazza wrote:

On Thursday, June 1, 2017 9:32 PM, Vladimir.S <svabox@gmail.com> wrote:

On 01.06.2017 19:31, Tommaso Piazza wrote:
> Dear all,
>
> I made a comparison of Swift's 4 lack of tuple unsplatting, here is how it stands in
> comparison with other languages
>
> https://gist.github.com/blender/53f9568617654c38a219dd4a8353d935
>

Thank you! Very useful information. And also I really like the opinion of
@AliSoftware in comments for this article.

I'd suggest to add this variant to Swift section in your article:

let eighteenOrMore = ["Tom" : 33, "Rebecca" : 17, "Siri" : 5].filter {
     (arg: (name: String, age: Int)) in arg.age >= 18 }

(I believe it is better that 2 others Swift variants.)

It seems for me that we need to allow some special syntax for *explicit* tuple
destructuring in closures to make all happy.

FWIW These suggestions are my favorite:

1. Just allow type inference for tuple's destructured variables in this position:

.filter { (arg: (name, age)) in arg.age >= 18 }

2. (1) + allow underscore for tuple argument name:

.filter { (_: (name, age)) in age >= 18 }

3. (2) + allow to omit parenthesis (probably only in case of just one tuple argument)

.filter { _: (name, age) in age >= 18 }

4. Use pattern matching syntax:

.filter { case let (name, age) in age >= 18 }

(looks similar as allowed today: if case let (name, age) = x { print(name, age) } )

5. Use two pairs of parenthesis :

.filter { ((name, age)) in age >= 18 }

Btw, about the 5th variant. If took what is allowed today:
.filter { (arg: (name: String, age: Int)) in arg.age >= 18 }
, and allow type inference for tuple part arguments, we'll have this:
.filter { (arg: (name, age)) in arg.age >= 18 }
, and if additionally allow skipping of tuple argument declaration we'll have:
.filter { ((name, age)) in arg.age >= 18 }
I.e. two pairs for parenthesis for tuple destructuring, and such syntax is similar to
the type this closure should have : ((String, Int)) -> Bool

>
> On Thursday, June 1, 2017 12:25 PM, Vladimir.S via swift-evolution > > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> On 01.06.2017 0:42, John McCall wrote:
> >> On May 31, 2017, at 2:02 PM, Stephen Celis <stephen.celis@gmail.com > <mailto:stephen.celis@gmail.com> > > <mailto:stephen.celis@gmail.com <mailto:stephen.celis@gmail.com>>> wrote:
> >>> On May 28, 2017, at 7:04 PM, John McCall via swift-evolution > > >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
> >>>
> >>> Yes, I agree. We need to add back tuple destructuring in closure parameter
> >>> lists because this is a serious usability regression. If we're reluctant to
> >>> just "do the right thing" to handle the ambiguity of (a,b), we should at least
> >>> allow it via unambiguous syntax like ((a,b)). I do think that we should just
> >>> "do the right thing", however, with my biggest concern being whether there's
> >>> any reasonable way to achieve that in 4.0.
> >>
> >> Closure parameter lists are unfortunately only half of the equation here. This
> >> change also regresses the usability of point-free expression.
> >
> > The consequences for point-free style were expected and cannot really be
> > eliminated without substantially weakening SE-0110. Closure convenience seems to
> > me to be a much more serious regression.
>
> John, do you also want to say "and without weakening SE-0066"? Because, if I
> understand correctly, in this case:
>
> func add(_ x: Int, _ y: Int) -> Int {
> return x + y
> }
>
> zip([1, 2, 3], [4, 5, 6]).map(add)
>
> .. we have a clear function type mismatch situation, when map() expects function of
> type ((Int, Int))->Int, but function of type (Int,Int)->Int is provided ? So probably
> the additional 'reason' of the 'problem' in this case is SE-0066, no?
> Or I don't understand the SE-0066 correctly..
> Do we want to allow implicit conversions between function type ((Int,Int))->Int and
> (Int,Int)->Int?
>
> Quote from SE-0066:
> ---
> (Int, Int) -> Int // function from Int and Int to Int
> ((Int, Int)) -> Int // function from tuple (Int, Int) to Int
> ---
>
> During this discussion I see a wish of some group of developers to just return back
> tuple splatting for function/closure arguments, so they can freely send tuple to
> function/closure accepting a list of parameters(and probably vise-versa).
> Is it worth to follow SE-0066 and SE-0110 as is, i.e. disallow tuple deconstructing
> and then, as additive change improve the situation with tuple
> splatting/deconstructing later with separate big proposal?
>
> Btw, about the SE-0110 proposal. It was discussed, formally reviewed and accepted. I
> expect that its revision also should be formally proposed/reviewed/accepted to
> collect a wide range of opinions and thoughts, and attract the attention of
> developers in this list to the subject.
>
> Also, if we revisit SE-0110, will this code be allowed?:
>
> func foo(_ callback: ((Int,Int))->Void) {}
> let mycallback = {(x:Int, y:Int)->Void in }
> foo(mycallback)
>
> and
>
> func foo(_ callback: (Int,Int)->Void) {}
> let mycallback = {(x: (Int, Int))->Void in }
> foo(mycallback)
>
> If so, what will be result of this for both cases? :
>
> print(type(of:mycallback)) // (Int,Int)->Void or ((Int,Int))->Void
>
> If allowed, do we want to allow implicit conversion between types (Int,Int)->Void and
> ((Int,Int))->Void in both directions? (Hello tuple splatting?)
>
> >
> > John.
> >
> >>
> >> func add(_ x: Int, _ y: Int) -> Int { return x + y }
> >>
> >> zip([1, 2, 3], [4, 5, 6]).map(add)
> >>
> >> // error: nested tuple parameter '(Int, Int)' of function '(((_.Element,
> >> _.Element)) throws -> _) throws -> [_]' does not support destructuring
> >>
> >> This may not be a common pattern in most projects, but we heavily use this style
> >> in the Kickstarter app in our functional and FRP code. Definitely not the most
> >> common coding pattern, but a very expressive one that we rely on.
> >>
> >> Our interim solution is a bunch of overloaded helpers, e.g.:
> >>
> >> func tupleUp<A, B, C>(_ f: (A, B) -> C) -> ((A, B)) -> C { return }
> >>
> >> zip([1, 2, 3], [4, 5, 6]).map(tupleUp(add))
> >>
> >> Stephen
> >
> > .
> >
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>

> https://lists.swift.org/mailman/listinfo/swift-evolution
>

+1 to this.

In practice, we have seen that the previous behaviour was incredibly
versatile and it allowed for more expressive code; using tuples in generic
types is much more pleasant to use (eg: Dictionary and similar
collections). I suppose most users of that Dictionary API did not know that
those blocks were accepting tuples and not several parameters, but still
they were productive with those APIs. Now we will require them to know what
I consider is a implementation detail, which adds a small cognitive load
when they try to use them.

So, which syntax is considered to be better? To me, every proposed syntax
is worse than the previous one, even more considering that this will be a
breaking change. And we do not need to invent some examples, we have real
usages that we can reason about:

        return components.map { "\($0)=\($1)" }.joined(separator: "&")

I suppose that with Swift 4 that line of code will be rewritten as this:

        return components.map { "\($0.0)=\($0.1)" }.joined(separator: "&")

No matter the workaround, that will be the case. That is not Swift code I
want to write nor maintain.

Can't we delay the release of SE-0110 until Swift 5, where we can reason
more about its consequences? Are the gains in compilation times so
impressive? Do we want to hinder such code patterns because of "type
safety"? Are there any real world examples where that has been an issue?

Thanks,

···

On Mon, Jun 5, 2017 at 9:31 AM, Gwendal Roué via swift-evolution < swift-evolution@swift.org> wrote:

The motivation section is not at all about any "type checker problem".
It's about a postulate that has been proven horribly source-breaking, and
counter-productive. The type safety argument is moot. The principle of
least surprise has been blown away by SE-0110, putting Swift aside from the
majority of other languages.

I'm surprised that everybody tries to workaround SE-0110 consequences,
admitting that it's relevant, instead of revisiting SE-0110 at its very
root.

Gwendal

--
Víctor Pimentel

The migrator does not properly distinquish between single-tuple and multiple-argument function types as described in SE–0110, causing additional mismatched type errors with the closure types that are passed to Standard Library functions expecting tuple objects. (32431899)

Workaround: Manually fix the closure types to accept values of tuples instead of separate argument values.

When using $0 and $1 in a closure that is passed to a function expecting a closure with a single tuple argument, the compiler may error after migration with:

    error: closure tuple parameter '(TYPE, TYPE)' does not support
    destructuring with implicit parameters
(32489893)

Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively.

Where are the firemen?

Gwendal

We discussed this in the core team meeting today. Consensus seems to be that a change needs to be made to regain syntactic convenience here. Discussion was leaning towards allowing (at least) the parenthesized form, but more discussion is needed.

One (tangential) thing that came up is that tuple element names in tuple *patterns* should probably be deprecated and removed at some point. Without looking, what variables does this declare?:

  let (a : Int, b : Float) = foo()

?

-Chris

···

On Jun 12, 2017, at 10:07 PM, Paul Cantrell <cantrell@pobox.com> wrote:

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

I think the goal of SE 0110 and to a lesser extent 0066 was to disallow this level of intelligence in the compiler.

Interesting.

I happen to think that the goal of SE–110 <https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md&gt; was to make Swift's type system “properly distinguish between functions that take one tuple argument, and functions that take multiple arguments.” Nowhere does that proposal discuss tuple destructuring, and nowhere does it discuss optional parentheses around closure parameter lists.

I might go so far as to say that any commits which *do* affect those things, cannot possibly be correct implementations of the accepted proposal SE–110, because SE–110 did not describe any changes there.

With SE–66 <https://github.com/apple/swift-evolution/blob/master/proposals/0066-standardize-function-type-syntax.md&gt; the case is even more clearcut: that proposal explicitly addresses the question, “Should we require parentheses in closure expression parameter lists?“ and answers it in the negative. The core team’s notes <https://lists.swift.org/pipermail/swift-evolution-announce/2016-May/000138.html&gt; on accepting also specify, “The core team did not feel that this proposal needed to include required parentheses within closures, which have their own fairly specific grammar.”

While technically feasible, it's not desirable to overload parentheses in this manner.

I strongly disagree. Language features are desirable exactly to the extent that they make life better for developers.

Moreover, parentheses are *already* optional in closure parameter lists. Making them mandatory would be source-breaking for no benefit to programmers. Plus having to write double-parentheses in “dict.map{ ((key, value)) in … }” would be needlessly annoying.

This is basically my perspective. There are language features where we've made an intentional decision to require the user to write things in a specific way. Closure parameter lists are not one of them; we've already committed to using a very permissive and flexible grammar. Perhaps that was a mistake, but it's a mistake we've made and cannot reasonably undo, notwithstanding the proposals that are basically "we should ban such-and-such style that, coincidentally, I happen not to use." In the long term, I feel confident that we can deliver an implementation that resolves the multiple-parameter vs. tuple-decomposition ambiguity without making any significant compromises, but I'm not sure whether we can reasonably achieve that in 4.0.

John.

As far as I can tell, right now is the earliest possible opportunity for us to get real feedback on the impact of this proposal.

Therefore, it seems unfortunate that the apparent response is that it is already too late to fix the problem. Or, perhaps I am misunderstanding?

- Tony

···

On May 31, 2017, at 1:16 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On May 30, 2017, at 7:41 AM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mon, May 29, 2017 at 10:47 PM, Robert Bennett <rltbennett@icloud.com <mailto:rltbennett@icloud.com>> wrote:

In my view there have been far too many calls for making Swift “consistent” in ways that actually make it less enjoyable to use. That is the opposite of “Swifty”, and we should instead prioritize convenience for users above rigid consistency of implementation.

In the case at hand, with Dictionary.map, the vast majority of the time the user doesn’t actually care whether the closure takes two arguments or a single 2-tuple argument. They just know that it takes a key and a value, and they want to be able to write “dict.map{ (key, value) in … }”.

Sure, the closure *does* take a 2-tuple, and it does not take two arguments, but the programmer *using* it shouldn’t have to bother about that distinction most of the time. They just want to assign the key to one identifier and the value to another. If they try to write “key, value” without any parentheses the compiler will complain and they’ll add the parens. But if the compiler demands a *second* set of parentheses, that will just seem ridiculous.

Nevin
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Thanks, added.

Is the version you suggest to add to my list for the Swift syntax currently valid as
of SE-0110 in Swift 4?

Yes, just checked on latest dev snapshot of Swift 4.

···

On Friday, June 2, 2017 1:18 PM, Vladimir.S <svabox@gmail.com> wrote:
On 02.06.2017 2:34, Tommaso Piazza wrote:

On Thursday, June 1, 2017 9:32 PM, Vladimir.S <svabox@gmail.com> wrote:

On 01.06.2017 19:31, Tommaso Piazza wrote:
> Dear all,
>
> I made a comparison of Swift's 4 lack of tuple unsplatting, here is how it stands in
> comparison with other languages
>
> https://gist.github.com/blender/53f9568617654c38a219dd4a8353d935
>

Thank you! Very useful information. And also I really like the opinion of
@AliSoftware in comments for this article.

I'd suggest to add this variant to Swift section in your article:

let eighteenOrMore = ["Tom" : 33, "Rebecca" : 17, "Siri" : 5].filter {
(arg: (name: String, age: Int)) in arg.age >= 18 }

(I believe it is better that 2 others Swift variants.)

It seems for me that we need to allow some special syntax for *explicit* tuple
destructuring in closures to make all happy.

FWIW These suggestions are my favorite:

1. Just allow type inference for tuple's destructured variables in this position:

.filter { (arg: (name, age)) in arg.age >= 18 }

2. (1) + allow underscore for tuple argument name:

.filter { (_: (name, age)) in age >= 18 }

3. (2) + allow to omit parenthesis (probably only in case of just one tuple argument)

.filter { _: (name, age) in age >= 18 }

4. Use pattern matching syntax:

.filter { case let (name, age) in age >= 18 }

(looks similar as allowed today: if case let (name, age) = x { print(name, age) } )

5. Use two pairs of parenthesis :

.filter { ((name, age)) in age >= 18 }

Btw, about the 5th variant. If took what is allowed today:
.filter { (arg: (name: String, age: Int)) in arg.age >= 18 }
, and allow type inference for tuple part arguments, we'll have this:
.filter { (arg: (name, age)) in arg.age >= 18 }
, and if additionally allow skipping of tuple argument declaration we'll have:
.filter { ((name, age)) in arg.age >= 18 }
I.e. two pairs for parenthesis for tuple destructuring, and such syntax is similar to
the type this closure should have : ((String, Int)) -> Bool

>
>
>
> On Thursday, June 1, 2017 12:25 PM, Vladimir.S via swift-evolution > > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>
> On 01.06.2017 0:42, John McCall wrote:
> >> On May 31, 2017, at 2:02 PM, Stephen Celis <stephen.celis@gmail.com > <mailto:stephen.celis@gmail.com> > > <mailto:stephen.celis@gmail.com <mailto:stephen.celis@gmail.com>>> wrote:
> >>> On May 28, 2017, at 7:04 PM, John McCall via swift-evolution > > >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
> >>>
> >>> Yes, I agree. We need to add back tuple destructuring in closure parameter
> >>> lists because this is a serious usability regression. If we're reluctant to
> >>> just "do the right thing" to handle the ambiguity of (a,b), we should at least
> >>> allow it via unambiguous syntax like ((a,b)). I do think that we should just
> >>> "do the right thing", however, with my biggest concern being whether there's
> >>> any reasonable way to achieve that in 4.0.
> >>
> >> Closure parameter lists are unfortunately only half of the equation here. This
> >> change also regresses the usability of point-free expression.
> >
> > The consequences for point-free style were expected and cannot really be
> > eliminated without substantially weakening SE-0110. Closure convenience seems to
> > me to be a much more serious regression.
>
> John, do you also want to say "and without weakening SE-0066"? Because, if I
> understand correctly, in this case:
>
> func add(_ x: Int, _ y: Int) -> Int {
> return x + y
> }
>
> zip([1, 2, 3], [4, 5, 6]).map(add)
>
> .. we have a clear function type mismatch situation, when map() expects function of
> type ((Int, Int))->Int, but function of type (Int,Int)->Int is provided ? So probably
> the additional 'reason' of the 'problem' in this case is SE-0066, no?
> Or I don't understand the SE-0066 correctly..
> Do we want to allow implicit conversions between function type ((Int,Int))->Int and
> (Int,Int)->Int?
>
> Quote from SE-0066:
> ---
> (Int, Int) -> Int // function from Int and Int to Int
> ((Int, Int)) -> Int // function from tuple (Int, Int) to Int
> ---
>
> During this discussion I see a wish of some group of developers to just return back
> tuple splatting for function/closure arguments, so they can freely send tuple to
> function/closure accepting a list of parameters(and probably vise-versa).
> Is it worth to follow SE-0066 and SE-0110 as is, i.e. disallow tuple deconstructing
> and then, as additive change improve the situation with tuple
> splatting/deconstructing later with separate big proposal?
>
> Btw, about the SE-0110 proposal. It was discussed, formally reviewed and accepted. I
> expect that its revision also should be formally proposed/reviewed/accepted to
> collect a wide range of opinions and thoughts, and attract the attention of
> developers in this list to the subject.
>
>
> Also, if we revisit SE-0110, will this code be allowed?:
>
> func foo(_ callback: ((Int,Int))->Void) {}
> let mycallback = {(x:Int, y:Int)->Void in }
> foo(mycallback)
>
> and
>
> func foo(_ callback: (Int,Int)->Void) {}
> let mycallback = {(x: (Int, Int))->Void in }
> foo(mycallback)
>
> If so, what will be result of this for both cases? :
>
> print(type(of:mycallback)) // (Int,Int)->Void or ((Int,Int))->Void
>
> If allowed, do we want to allow implicit conversion between types (Int,Int)->Void and
> ((Int,Int))->Void in both directions? (Hello tuple splatting?)
>
>
> >
> > John.
> >
> >
> >>
> >> func add(_ x: Int, _ y: Int) -> Int { return x + y }
> >>
> >> zip([1, 2, 3], [4, 5, 6]).map(add)
> >>
> >> // error: nested tuple parameter '(Int, Int)' of function '(((_.Element,
> >> _.Element)) throws -> _) throws -> [_]' does not support destructuring
> >>
> >> This may not be a common pattern in most projects, but we heavily use this style
> >> in the Kickstarter app in our functional and FRP code. Definitely not the most
> >> common coding pattern, but a very expressive one that we rely on.
> >>
> >> Our interim solution is a bunch of overloaded helpers, e.g.:
> >>
> >> func tupleUp<A, B, C>(_ f: (A, B) -> C) -> ((A, B)) -> C { return }
> >>
> >> zip([1, 2, 3], [4, 5, 6]).map(tupleUp(add))
> >>
> >> Stephen
> >
> > .
> >
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
<mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>

> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>

Wait, there's more!

When passing a closure with a single underscore argument ({ _ in ...}) to a function expecting multiple arguments, the compiler may error after migration with:

    error: cannot convert value of type '(_) -> ()' to expected argument
    type
(32301091)
Workaround: To fix the error, change the single argument to the correct number of arguments

such as { (_,_) in ...}

When passing a closure to map with two function arguments, the compiler may after migration error with:

       error: 'map' produces '[T]', not the expected contextual result type
       '<TYPE>'
(32432752)
Workaround: Change the closure signature to accept a tuple argument of two elements when

using map.

Gwendal

···

Le 6 juin 2017 à 06:36, Gwendal Roué <gwendal.roue@gmail.com> a écrit :

Unauthorized - Apple Developer

The migrator does not properly distinquish between single-tuple and multiple-argument function types as described in SE–0110, causing additional mismatched type errors with the closure types that are passed to Standard Library functions expecting tuple objects. (32431899)

Workaround: Manually fix the closure types to accept values of tuples instead of separate argument values.

When using $0 and $1 in a closure that is passed to a function expecting a closure with a single tuple argument, the compiler may error after migration with:

    error: closure tuple parameter '(TYPE, TYPE)' does not support
    destructuring with implicit parameters
(32489893)

Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively.

Where are the firemen?

Gwendal

Unauthorized - Apple Developer

The migrator does not properly distinquish between single-tuple and multiple-argument function types as described in SE–0110, causing additional mismatched type errors with the closure types that are passed to Standard Library functions expecting tuple objects. (32431899)

Workaround: Manually fix the closure types to accept values of tuples instead of separate argument values.

When using $0 and $1 in a closure that is passed to a function expecting a closure with a single tuple argument, the compiler may error after migration with:

error: closure tuple parameter '(TYPE, TYPE)' does not support destructuring with implicit parameters

(32489893)

Workaround: Change $0 and $1 references to $0.0 and $0.1 respectively.

Where are the firemen?

Could you help me to understand which of my question did you reply on with the above link and quotes? What are you trying to say? Thank you.

···

On 06.06.2017 7:36, Gwendal Roué wrote:

Gwendal

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

We discussed this in the core team meeting today. Consensus seems to be that a change needs to be made to regain syntactic convenience here. Discussion was leaning towards allowing (at least) the parenthesized form, but more discussion is needed.

One (tangential) thing that came up is that tuple element names in tuple *patterns* should probably be deprecated and removed at some point. Without looking, what variables does this declare?:

  let (a : Int, b : Float) = foo()

Personally, I use this often as "anonymous structs" (which tuples IMHO are). Often, there is a return type used in 1-2 methods and in such case, I feel that declaring a struct MyMethorReturnStruct is unnecessary and I use tuples with named elements, so that the call site can easily access the information it needs, which is particularly convenient if both tuple member are of the same type:

func parseName() -> (firstName: String, lastName: String)

Instead of deprecating this, would it be possible to make this a syntax for generating a truly anonymous structure? It can internally have a name that mangles together the element *names and types*, so:

let name = (firstName: "John", lastName: "Doe")

type(of: name) == _firstName_String_lastName_String_

Hence you would be able to pass this structure wherever it's declared exactly the same, but:

func passName() -> (name1: String, name2: String) {
  return parseName() // see above for declaration
}

will result in error as (firstName: String, lastName: String) cannot be converted to (name1: String, name2: String).

···

On Jun 15, 2017, at 6:01 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 12, 2017, at 10:07 PM, Paul Cantrell <cantrell@pobox.com> wrote:

?

-Chris

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

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

We discussed this in the core team meeting today. Consensus seems to be that a change needs to be made to regain syntactic convenience here. Discussion was leaning towards allowing (at least) the parenthesized form, but more discussion is needed.

One (tangential) thing that came up is that tuple element names in tuple *patterns* should probably be deprecated and removed at some point. Without looking, what variables does this declare?:

   let (a : Int, b : Float) = foo()

Another option would be to require let to appear next to each name binding instead of allowing a single let for the whole pattern. I personally find that much more clear despite it being a little bit more verbose.

···

Sent from my iPad

On Jun 14, 2017, at 11:01 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 12, 2017, at 10:07 PM, Paul Cantrell <cantrell@pobox.com> wrote:

?

-Chris

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

It declares variables Int and Float, but I know that only because CodaFi asked us the same question on twitter a while back! I'd be very happy if that was deprecated.

···

On 15 Jun 2017, at 06:01, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 12, 2017, at 10:07 PM, Paul Cantrell <cantrell@pobox.com> wrote:

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

We discussed this in the core team meeting today. Consensus seems to be that a change needs to be made to regain syntactic convenience here. Discussion was leaning towards allowing (at least) the parenthesized form, but more discussion is needed.

One (tangential) thing that came up is that tuple element names in tuple *patterns* should probably be deprecated and removed at some point. Without looking, what variables does this declare?:

   let (a : Int, b : Float) = foo()

?

-Chris

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

Sorry, but I'm utterly confused: the output from the Core Team meeting about regressions caused by restrictions imposed in SE-0110 is that... the compiler should add more restrictions??

···

On 15 Jun 2017, at 06:01, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 12, 2017, at 10:07 PM, Paul Cantrell <cantrell@pobox.com> wrote:

What’s the status of this Chris’s double parens idea below? It garnered some positive responses, but the discussion seems to have fizzled out. Is there something needed to help nudge this along?

What’s the likelihood of getting this fixed before Swift 4 goes live, and the great wave of readability regressions hits?

We discussed this in the core team meeting today. Consensus seems to be that a change needs to be made to regain syntactic convenience here. Discussion was leaning towards allowing (at least) the parenthesized form, but more discussion is needed.

One (tangential) thing that came up is that tuple element names in tuple *patterns* should probably be deprecated and removed at some point. Without looking, what variables does this declare?:

   let (a : Int, b : Float) = foo()

?

--
Víctor Pimentel

I think the goal of SE 0110 and to a lesser extent 0066 was to disallow this level of intelligence in the compiler.

Interesting.

I happen to think that the goal of SE–110 <https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md&gt; was to make Swift's type system “properly distinguish between functions that take one tuple argument, and functions that take multiple arguments.” Nowhere does that proposal discuss tuple destructuring, and nowhere does it discuss optional parentheses around closure parameter lists.

I might go so far as to say that any commits which *do* affect those things, cannot possibly be correct implementations of the accepted proposal SE–110, because SE–110 did not describe any changes there.

With SE–66 <https://github.com/apple/swift-evolution/blob/master/proposals/0066-standardize-function-type-syntax.md&gt; the case is even more clearcut: that proposal explicitly addresses the question, “Should we require parentheses in closure expression parameter lists?“ and answers it in the negative. The core team’s notes <https://lists.swift.org/pipermail/swift-evolution-announce/2016-May/000138.html&gt; on accepting also specify, “The core team did not feel that this proposal needed to include required parentheses within closures, which have their own fairly specific grammar.”

While technically feasible, it's not desirable to overload parentheses in this manner.

I strongly disagree. Language features are desirable exactly to the extent that they make life better for developers.

Moreover, parentheses are *already* optional in closure parameter lists. Making them mandatory would be source-breaking for no benefit to programmers. Plus having to write double-parentheses in “dict.map{ ((key, value)) in … }” would be needlessly annoying.

This is basically my perspective. There are language features where we've made an intentional decision to require the user to write things in a specific way. Closure parameter lists are not one of them; we've already committed to using a very permissive and flexible grammar. Perhaps that was a mistake, but it's a mistake we've made and cannot reasonably undo, notwithstanding the proposals that are basically "we should ban such-and-such style that, coincidentally, I happen not to use." In the long term, I feel confident that we can deliver an implementation that resolves the multiple-parameter vs. tuple-decomposition ambiguity without making any significant compromises, but I'm not sure whether we can reasonably achieve that in 4.0.

John.

As far as I can tell, right now is the earliest possible opportunity for us to get real feedback on the impact of this proposal.

Therefore, it seems unfortunate that the apparent response is that it is already too late to fix the problem. Or, perhaps I am misunderstanding?

I am not trying to say that it is too late to fix the problem. Some solutions might be off the table, but we need to investigate what we can do.

John.

···

On May 31, 2017, at 3:42 PM, Tony Parker <anthony.parker@apple.com> wrote:

On May 31, 2017, at 1:16 PM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 30, 2017, at 7:41 AM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mon, May 29, 2017 at 10:47 PM, Robert Bennett <rltbennett@icloud.com <mailto:rltbennett@icloud.com>> wrote:

- Tony

In my view there have been far too many calls for making Swift “consistent” in ways that actually make it less enjoyable to use. That is the opposite of “Swifty”, and we should instead prioritize convenience for users above rigid consistency of implementation.

In the case at hand, with Dictionary.map, the vast majority of the time the user doesn’t actually care whether the closure takes two arguments or a single 2-tuple argument. They just know that it takes a key and a value, and they want to be able to write “dict.map{ (key, value) in … }”.

Sure, the closure *does* take a 2-tuple, and it does not take two arguments, but the programmer *using* it shouldn’t have to bother about that distinction most of the time. They just want to assign the key to one identifier and the value to another. If they try to write “key, value” without any parentheses the compiler will complain and they’ll add the parens. But if the compiler demands a *second* set of parentheses, that will just seem ridiculous.

Nevin
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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