[swift-evolution] Proposal: Always flatten the single element tuple
Vladimir.S
svabox at gmail.com
Wed Jun 7 10:15:24 CDT 2017
On 07.06.2017 16:20, Gwendal Roué wrote:
>
>> Le 7 juin 2017 à 15:11, Xiaodi Wu <xiaodi.wu at gmail.com
>> <mailto:xiaodi.wu at gmail.com>> a écrit :
>>
>> While SE-0025 was generally regarded as unfortunate, the thousands of emails that
>> followed relitigating it were much, much worse.
>>
>> The removal of implicit tuple splatting, which is *not* SE-0110, was approved on
>> the understanding that it would be a regression until explicit tuple splatting is
>> introduced. This tradeoff was considered and approved. It’s clear that you
>> disagree, but that is not grounds to divert a necessary discussion on mitigating
>> SE-0110 into relitigating something else.
>
> Push me out if you want, but will you push out those blatant wounds out as well?
>
> Example 1
> - return columns.index { (column, _) in column.lowercased() == lowercaseName }
> + return columns.index { $0.0.lowercased() == lowercaseName }
Why not
columns.index { (arg: (column: String, _: Int)) in arg.column.lowercased() ==
lowercaseName }
?
Yes, I understand that first syntax short and not verbose, but the alternative you
provided IMHO much worse than explicit type declaration in closure.
>
> Example 2 :
> - .map { (mappedColumn, baseColumn) -> (Int, String) in
> + .map { (pair) -> (Int, String) in
> + let mappedColumn = pair.key
> + let baseColumn = pair.value
>
Can't compile something like this even in Swift 3, could you provide a small code
snippet for this?
> Example 3 :
> - .map { (table,
> columns) in "\(table)(\(columns.sorted().joined(separator: ", ")))" }
> + .map { "\($0.key)(\($0.value.sorted().joined(separator: ", ")))" }
Same, why not
.map { (arg: (table: String, columns: [String])) in
"\(arg.table)(\(arg.columns.sorted().joined(separator: ", ")))" }
>
> Example 4 :
> - dictionary.first { (column, value) in column.lowercased() ==
> orderedColumn.lowercased() }
> + dictionary.first { $0.key.lowercased() == orderedColumn.lowercased() }
>
Same.
> See also messages from Stephen Cellis, who shows how other kinds of developer code
> has lost expressivity and clarity with those changes that have been "considered and
> approved".
>
Gwendal, no one saying that new syntax is better, that it is good thing that we lost
the short syntax for tuple argumment deconstructions in closures.
But there is just no easy/obvious way to keep that syntax in Swift 4. The problem
can't be solved just by not implementing SE-0110, as in Swift4 we should have two
separate function types: one that takes single tuple argument and second that accepts
a list of arguments, i.e. (Int,Int)->() and ((Int,Int))->() should be two different
types now.
This is not just SE-0110, this is also SE-0066, so, to be correct, you should propose
to revisit it also.
Please look here:
func foo(_ x: Int, _ y: Int) {} // type(of: foo) should be (Int, Int)->()
func bar(_ x (Int, Int)) {} // type(of: bar) should be ((Int, Int))->()
The above is described in SE-0066. Then, you have a closure constants:
var fooClosure = {(x: Int, y: Int) in }
var barClosure = {(x: (Int, Int)) in }
what should be types of these closures? Obvious the same: (Int,Int)->() and
((Int,Int))->() respectively.
Then you have a func that accepts ((Int,Int))->Int closure:
func schedule(callback: ((Int,Int))->()) {..}
, given type of foo func is (Int, Int)->() , do you suggest to allow sending foo to
'schedule' func? The same question is for fooClosure
schedule(callback: foo) // ??
schedule(callback: fooClosure) // ??
Probably we can(if technically possible, I don't know) to always allow sending of
function/closure with list of arguments when function with one tuple is required. I
don't know how such exceptional rule would looks like inside type system of Swift,
what should be result of 'foo is ((Int,Int))->()' then and 'type(of:foo) ==
type(of:bar)' in such case.
But this requires a formal proposal, review period and implementation(as I
understand, better before Swift 4 release). Probably you can submit such proposal, go
through the review period and help with implementation.
In this case we'll have the same user-friendly closure/function parameters expirience
but with respect to correct function types.
But currently we have a situation: argument of type ((Int,Int))->() is required, and
we provide argument of another type : (Int,Int)->() i.e. incorrect type.
The only obvious solution here is using the common rule for type mismatch - disallow
this.
Currently we have a number of suggestions how we can improve usability for the
discussed problem:
* use 'let' syntax in closure argument list to deconstruct tuple argument
* use doubled parenthesis to deconstruct tuple argument: { ((key, value)) in .. }
* generation of closure of correct type if closure is declared inside function call
and arguments have no type annotations, i.e.
//schedule(callback: foo) // disallowed, type mismatch
//schedule(callback: fooClosure) // disallowed, type mismatch
// allowed. compiler will generate closure of type ((Int,Int))->() from this code
schedule { x,y in }
// type mismatch, this syntax defines closure of (Int,Int)->() type
//schedule { (x: Int, y: Int) in }
But because all of this are additional features that can be added later, and each
required to be reviewed/discussed in details, core team can decide to delay such
'fix' for after-release period. Let's wait and see what core team had to say about
this subject.
> Cheers,
> Gwendal
>
More information about the swift-evolution
mailing list