[swift-evolution] Revisiting SE-0110

Vladimir.S svabox at gmail.com
Fri Jun 2 09:31:50 CDT 2017


John and others, who are involved into this thread.
I'd suggest to clarify the current(Swift4) situation with function/closure type 
before we make any other decision and before continue to discuss the subject.
(sorry for long email, but I feel the problem with SE-0110 is wider than just "let's 
just drop it")

Please review this code and its result 
(swift-4.0-DEVELOPMENT-SNAPSHOT-2017-06-01-a-osx) :

func fooParam(_ x: Int, _ y: Int){}
func fooTuple(_ x: (Int, Int)) {}

print("type of fooParam is", type(of:fooParam))
// type of fooParam is (Int, Int) -> ()

print("type of fooTuple is", type(of:fooTuple))
// type of fooTuple is (Int, Int) -> ()

print("type of fooParam == type of fooTuple ?", type(of: fooParam) == type(of: 
fooTuple))
// true

if fooParam is (Int,Int)->() { print("fooParam is (Int,Int)->()") }
// fooParam is (Int,Int)->()

if fooParam is ((Int,Int))->() { print("fooParam is ((Int,Int))->()") }
// fooParam is ((Int,Int))->()

if fooTuple is (Int,Int)->() { print("fooTuple is (Int,Int)->()") }
// fooTuple is (Int,Int)->()

if fooTuple is ((Int,Int))->() { print("fooTuple is ((Int,Int))->()") }
// fooTuple is ((Int,Int))->()


var closureParam = { (x: Int, y: Int) in  }
var closureTuple = { (x: (Int, Int)) in  }

print("type of closureParam is", type(of:closureParam))
// type of closureParam is (Int, Int) -> ()

print("type of closureTuple is", type(of:closureTuple))
// type of closureTuple is (Int, Int) -> ()

if closureParam is (Int,Int)->() { print("closureParam is (Int,Int)->()") }
// closureParam is (Int,Int)->()

if closureParam is ((Int,Int))->() { print("closureParam is ((Int,Int))->()") }
// closureParam is ((Int,Int))->()

if closureTuple is (Int,Int)->() { print("closureTuple is (Int,Int)->()") }
// closureTuple is (Int,Int)->()

if closureTuple is ((Int,Int))->() { print("closureTuple is ((Int,Int))->()") }
// closureTuple is ((Int,Int))->()


func barParams(_ callback: (Int,Int)->()) { callback(1,2) }

//barParams(fooTuple)
//error: cannot convert value of type '((Int, Int)) -> ()' to expected argument type 
'(Int, Int) -> ()'

//barParams(closureTuple)
//error: cannot convert value of type '((Int, Int)) -> ()' to expected argument type 
'(Int, Int) -> ()'

func barTuple(_ callback: ((Int,Int))->()) { let tuple = (1,2); callback(tuple) }

//barTuple(fooParam)
//error: nested tuple parameter '(Int, Int)' of function '(((Int, Int)) -> ()) -> ()' 
does not support destructuring

//barTuple(closureParam)
//error: cannot convert value of type '(Int, Int) -> ()' to expected argument type 
'((Int, Int)) -> ()'


So, what is the type of fooParam/fooTuple/closureParam/closureTuple ?
Why the type is different in different situations?
Should we have strong and unambiguous type for functions/closures and probably *then* 
allow implicit conversion like "(Int,Int)->() can be used when ((Int,Int))->() is 
required and vise-versa"?

We have all this inconsistency with function/closure types from Swift 2, and this 
should be actually fixed in Swift 3, but still we are going to keep that in Swift 4.

Personally, I'm not against tuple deconstructing in closures and even think we can 
just have allowed implicit conversion between func/closure with single tuple argument 
and a list of arguments. But, I do believe we need consistent state in this area, 
strong types and clear rules. Because of this, if we have no time to implement good 
solution/workaround for Swift 4, I believe it is better to keep/fully implement 
SE-0110 and then provide solution for tuple destructuring. Otherwise we are going to 
have all these mess with func/closure types for very long time after Swift 4. Or we 
can try to implement a good workaround before release.

In current Swift 4 we are allowed for this:
.filter {(arg: (name: String, age: Int)) in arg.age >= 18 }

Is it really no way(before Swift 4 is released) to allow type inference for 'name' 
and 'age'? I believe this could be a good *workaround*, totally in Swift way(just 
like you can omit types for arguments in closure, or can specify them), this will 
keep the existed syntax for closure arguments and this will not prevent us from 
suggesting best solution after the Swift 4 release. And IMO this is acceptable 
compromise between loosing tuple deconstruction and keep the mess with 
function/closure type:
.filter {(arg: (name, age)) in arg.age >= 18 }

Or, as I said, just allow implicit conversion between function/closure types taking 
one tuple argument and a list of arguments. But still .filter should expect exactly 
((Int,String))->()  but it is allowed to send (Int,String)->() to it. All is strongly 
typed, but with magic "conversion".

I still believe that SE-0066 was the proposal that answered all these questions and 
said that (Int,Int)->() and ((Int,Int))->() are two different types. SE-0110 just 
clarified that the same rule should be applied to closures.
Until we started to discuss revisiting of SE-0110 I was under strong impression that 
SE-0066 was just partially implemented in Swift 3 and will be fully implemented only 
in Swift 4.

I even believe that information on SE-0066 page is not correct, that SE was NOT fully 
implemented for Swift 3 as described in the proposal header on site.
Could someone from core team please clarify, if they really think that proposal is 
fully implemented in current Swift 4.0 build?

I even ask(please, when you have a moment) Chris Lattner to look into this thread, 
because of his words in Rationale part of the SE-0110 acceptance message:

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

Seems like Chris at that moment also was thinking about SE-0110 just as bug fix for 
SE-0066/SE-0029 and so probably he can provide some useful information/thoughts about 
the subject.

Thank you for attention.
Vladimir.

On 02.06.2017 1:06, John McCall wrote:
> 
>> On Jun 1, 2017, at 2:39 PM, Pavol Vaskovic <pali at pali.sk <mailto:pali at pali.sk>> wrote:
>>
>> On Thu, Jun 1, 2017 at 8:52 PM, John McCall via swift-evolution 
>> <swift-evolution at swift.org <mailto:swift-evolution at 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.
> 
> John.
> 
>>
>> This is a HUGE regression to the usability of all closure with tuple arguments. I'd 
>> wager that is the prevailing consensual opinion of anyone who has experienced this 
>> issue in practice.
>>
>> I would go as far as to claim that current implementation of SE-0110 does not 
>> conform to the Swift 4's goal of backwards source compatibility.
>>
>>     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.
>>
>>
>> From what I understand our options are quite limited because of tight constraints 
>> of Swift 4's emphasis on backwards source-compatibility and impending release deadline:
>>
>> * effectively revert SE-0110 by always using the codepath for Swift 3 compatibility 
>> mode
>> * implement full tuple destructuring (unexplored issues with syntax and backwards 
>> compatibility)
>>
>> (Note that Swift 3 didn't support full tuple destructuring - SR-4738 
>> <https://bugs.swift.org/browse/SR-4738>)
>>
>> --Pavol
> 


More information about the swift-evolution mailing list