On 29.05.2017 21:08, Nevin Brackett-Rozinsky wrote:
Vladimir, using your function definitions I would like to have:
// Two parameters:
barParams{ t in } // invalid, too few parameters
barParams{ (t) in } // invalid, too few parameters
barParams{ x, y in } // valid, two parameters
barParams{ (x, y) in } // valid, two parameters with optional parentheses
barParams{ ((x, y)) in }// invalid, too few parameters
OK, the same as I suggest.
// One parameter which is a 2-tuple:
barTuple{ t in } // valid, one tuple parameter
barTuple{ (t) in } // valid, one tuple parameter with optional parentheses
barTuple{ x, y in } // invalid, too many parameters
OK..
barTuple{ (x, y) in } // valid, destructuring one tuple
barTuple{ ((x, y)) in } // valid, destructuring one tuple with optional
parentheses
Here is the problem for me. According to SE-0066 closure declared as {(x,y) in}
should be of type (Int,Int)->() and not ((Int,Int))->().
Why do you want to be able to pass wrong function/closure type into barTuple?
For completeness: if a closure takes *any number* of parameters, it should be legal
to list one identifier per parameter, separated by commas, with optionally a pair of
parentheses surrounding that list. Furthermore, if *any* parameter is a tuple, it
should be possible to replace the identifier corresponding to that parameter with a
pair of parentheses containing a number of identifiers (separated by commas) equal to
the arity of the tuple. And this tuple-destructuring should work recursively, so if a
tuple contains a tuple [contains a tuple…] the inner tuples may optionally be
destructured as well.
Well.. Theoretically I don't see any problem with this in suggested "double pair of
parentheses" syntax:
typealias MyTuple = (Int, (String, (Double, Bool)))
func doSomething(callback: ((Int, Int), MyTuple)->()) {}
doSomething {point, mytuple in }
doSomething {((x,y)), mytuple in }
doSomething {((x,y)), ((i, sdb)) in }
doSomething {point, ((i, ((s, ((d, b)))))) in }
//probably even just that flat syntax if all values are destructured
doSomething {((x, y)), ((i, s, d, b)) in }
doSomething {(t, myt) in } // here we see that there are 2 arguments, not tuples
doSomething {(((x,y)), myt) in }
doSomething {(((x,y)), ((i, tuple))) in }
doSomething {(point, ((i, ((s, ((d, b))))))) in }
the double parentheses in closure argument declaration clearly shows that this is a
tuple deconstruction.
The question if we'll decide to allow such feature(extended ability for tuple
deconstructing in closure arguments).
To be clear: each tuple being destructured must have a pair of parentheses containing
the identifiers it is being destructured into. It is only the very outermost
parentheses around the entire parameter list of the closure which should be optional.
I see your position, but as I said, IMO single pair of parentheses is very ambiguous
if it is a list of arguments or tuple deconstruction and we shouldn't disallow
single pair of parentheses to surround a simple list of closure arguments in declaration.
Nevin
On Mon, May 29, 2017 at 1:32 PM, Vladimir.S <[email protected]
<mailto:[email protected]>> wrote:
On 29.05.2017 18:26, Nevin Brackett-Rozinsky via swift-evolution wrote:
On Sun, May 28, 2017 at 7:04 PM, John McCall via swift-evolution
<[email protected] <mailto:[email protected]>
<mailto:[email protected] <mailto:[email protected]>>>
wrote:
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.
John.
I agree with John, the best thing for actually using Swift is to allow
tuple
destructuring here, and the outermost parentheses (around the entire
parameter list of a closure) should continue to be optional. Requiring
double-parens would seem unnecessarily and arbitrarily…whatever the
opposite
of “convenient” is.
Nevin
If I understand correctly, correct me if I'm wrong, after *full*
implementation
of SE-0066, the function with two parameters should have different type than
function with one tuple parameter:
I.e.
typealias FuncParams = (Int, Int)->()
typealias FuncTuple = ((Int, Int))->()
print(FuncParams.self) // should be (Int, Int)->()
print(FuncTuple.self) // should be ((Int, Int))->()
So, if we have
func barParams(_ f: FuncParams) {
f(1,2)
}
func barTuple(_ f: FuncTuple) {
f((1,2))
}
and
func fooWithParams(_ x: Int, _ y: Int) { }
func fooWithTuple(_ tuple: (Int, Int)) { }
.. we should not be able to call
barParams(fooWithTuple) // should be error: incompatible types
barTuple(fooWithParams) // should be error: incompatible types
If so, are you suggesting that this code should still be valid?
barParams({tuple in}) // ?
barTuple({x,y in}) // ?
Will {x,y in} closure has ((Int, Int))->() type in this case?
And if {tuple in} should be of type (Int,Int)->() ?
If I'm not missing something, the only reasonable solution here is follow
the
SE-0066 rules for function types and allow special syntax ((x,y)) to
deconstruct
tuple parts in closure argument list, and such closure will have type
((Int,Int))->() as expected. So we'll have:
barTuple({((x,y)) in ... })
_______________________________________________
swift-evolution mailing list
[email protected] <mailto:[email protected]>
https://lists.swift.org/mailman/listinfo/swift-evolution
<https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution