[swift-evolution] Revisiting SE-0110

Vladimir.S svabox at gmail.com
Sat May 27 07:01:34 CDT 2017

Regarding the requiring of parentheses for arguments in closures: I'd suggest to look 
into SE-0066's paragraph "Should we require parentheses in closure expression 
parameter lists?" and "Rationale" for this SE: 

Personally I agree that closures worth their own syntax and that it is important to 
keep closure's syntax lightweight. So, IMO we should keep {x, y in ..} syntax for 
closures and this should be jut equivalent for {(x, y) in ..}, i.e. one can use first 
or second depending on his/her style.

I think the idea of double parentheses for tuple argument destructing in closure is 
the best solution as it has a relationship to introduced by SE-0066 type of function 
with tuple argument. I.e.  :

func foo(_ x: (Int, Int)) {..}

type(of: foo) // should be ((Int, Int)) -> ()
// note: not  (Int, Int) -> ()

var g : ((Int, Int))->() = f

g = {((x1, x2)) in ... } // feels like correct syntax for type ((Int, Int))->()
g = {pair in ... } // also OK, single tuple argument

g = {(x1, x2) in ...} // should be ERROR: incompatible type of closure

But during the discussion of SE-0110 there was some negative reaction for this idea.

Btw, while we are discussing SE-0110 and SE-0066, I'd like to point to another change 
that can IMO have impact for functional programming, so I believe it is better to 
discuss this also.
Currently(Swift 3.1) we are allowed to have this:

var f : ()->() = {x in print(x)}
f() // ()
f = {_ in print(x)}

I.e. you can now assign a closure with single argument as function type that has 0 
parameters(because of implicit Void argument).

Also, after SE-0066 and 0110 implemented, passing Void to function declared without 
parameters should not be allowed, so for example you can't call f(print("sdfsdf")) 
i.e. can't pass result of Void to some other function that is declared without 

Small naive example:

func schedule<T>(with: T, do: (T) -> Void) {...}

//--- can't change this function for some reason ---
func foo() { .. } // just do something

current code:

schedule(with: (), do: foo)

new code:

schedule(with: (), do: {_ in foo()})

Actually I believe this is a good change, but should be taken into consideration.


On 26.05.2017 22:35, Robert Bennett via swift-evolution wrote:
> On the contrary I think the solution can absolutely be to break other code. Allowing 
> no parentheses is not a very useful shorthand -- it only saves two characters -- and 
> with SE-0110 actually obscures the logic. Always requiring parentheses makes it clear 
> that "{ (arg) in ..." can be replaced with "{ ((key, value)) in ..." when arg is a 
> 2-tuple; the outer parentheses denote an argument list, and anything inside them is 
> the argument, consistent with other parts of the language. Allowing "{ arg in ..." 
> but not "{ (key, value) in ..." is sure to leave some people scratching their heads 
> because"{ arg in ..." suggests that it is arguments that are passed to closures (as 
> is the case with functions) and not tuples. The correctness of "{ arg in ..." relies 
> too heavily on the equivalence between a 1-tuple and a single element, an equivalence 
> that does not hold for higher arities.
> I'm not *too* strongly wed to this, though. I care much more strongly about 
> allowing  "{ ((key, value)) in ..." than prohibiting  "{ arg in ...". I only brought 
> up the latter to try to improve the consistency of the language and to make clear 
> that  "{ ((key, value)) in ..." is the correct way of achieving the old style "{ 
> (key, value) in ..."
> On May 26, 2017, at 2:57 PM, Xiaodi Wu <xiaodi.wu at gmail.com 
> <mailto:xiaodi.wu at gmail.com>> wrote:
>> Requiring parentheses in closures like that was discussed during SE-0110 and 
>> rejected; the rationale was that it's a useful shorthand, and that the whole 
>> closure syntax is wildly different from function declarations: you don't need to 
>> write the type of the arguments, and you don't need to write the return value, so 
>> why would it make sense to enforce this particular formality?
>> At this point, I'd be very much against now requiring it. The whole rationale for 
>> revisiting SE-0110 is that it is breaking lots of code, and the solution cannot be 
>> to break lots of other code. The double parenthesis syntax or the let syntax for 
>> destructuring seem to be fine mitigations, the former because it strictly parallels 
>> the change in syntax in SE-0110 where a single tuple argument has two sets of 
>> parentheses, and the latter because it's the same destructuring syntax as is used 
>> elsewhere for pattern matching.
>> On Fri, May 26, 2017 at 11:45 David Sweeris via swift-evolution 
>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>     > On May 26, 2017, at 08:14, Robert Bennett via swift-evolution
>>     <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>     >
>>     > Alternatively, for maximum consistency we could make "{ arg in ..." illegal
>>     as well, requiring parentheses around "arg". This would mirror the parentheses
>>     necessary in e.g., "let f: (Int) -> Int", and there would be no confusion as to
>>     why " { arg in ..." is legal but not "{ (key, value) in ...".
>>     I think I would support that. Until quite recently, I was under the impression
>>     that closures' "inner signatures" were part of that proposal, anyway.
>>     (Come to think of it... were they? I suppose it could be a bug that the "old"
>>     syntax is still accepted here.)
>>     - Dave Sweeris
>>     _______________________________________________
>>     swift-evolution mailing list
>>     swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>     https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list