[swift-evolution] Revisiting SE-0110

John McCall rjmccall at apple.com
Thu Jun 1 13:52:04 CDT 2017

> On Jun 1, 2017, at 3:25 AM, Vladimir.S <svabox at gmail.com> wrote:
> On 01.06.2017 0:42, John McCall wrote:
>>> On May 31, 2017, at 2:02 PM, Stephen Celis <stephen.celis at gmail.com> wrote:
>>>> On May 28, 2017, at 7:04 PM, John McCall via swift-evolution
>>>> <swift-evolution at 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:

No.  SE-0066 was ultimately just a syntax proposal.  SE-0110 clarified the intended type-system behavior of function types for both calls and conversions.  Removing tuple destructuring from parameter clauses was an incidental consequence of that, which in my opinion was pursued out of enthusiasm and without adequately understanding the impact on closures.

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.  In contrast, I think we may be able to gain consensus on a more targeted proposal that just re-admits tuple destructuring in closures, assuming we can find an acceptable implementation.


> 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
>> .

More information about the swift-evolution mailing list