<div dir="ltr">I, for one, would be willing to accept Xiaodi&#39;s suggestion involving `let`–especially if (pipe dream follows) we could use the same syntax in functions/methods to destructure parameters.</div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jun 1, 2017 at 3:32 PM, Vladimir.S via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 01.06.2017 19:31, Tommaso Piazza wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Dear all,<br>
<br>
I made a comparison of Swift&#39;s 4 lack of tuple unsplatting, here is how it stands in comparison with other languages<br>
<br>
<a href="https://gist.github.com/blender/53f9568617654c38a219dd4a8353d935" rel="noreferrer" target="_blank">https://gist.github.com/blende<wbr>r/53f9568617654c38a219dd4a8353<wbr>d935</a><br>
<br>
</blockquote>
<br></span>
Thank you! Very useful information. And also I really like the opinion of @AliSoftware in comments for this article.<br>
<br>
I&#39;d suggest to add this variant to Swift section in your article:<br>
<br>
let eighteenOrMore = [&quot;Tom&quot; : 33, &quot;Rebecca&quot; : 17, &quot;Siri&quot; : 5].filter {<br>
        (arg: (name: String, age: Int)) in arg.age &gt;= 18 }<br>
<br>
(I believe it is better that 2 others Swift variants.)<br>
<br>
It seems for me that we need to allow some special syntax for *explicit* tuple destructuring in closures to make all happy.<br>
<br>
FWIW These suggestions are my favorite:<br>
<br>
1. Just allow type inference for tuple&#39;s destructured variables in this position:<br>
<br>
.filter { (arg: (name, age)) in arg.age &gt;= 18 }<br>
<br>
<br>
2. (1) + allow underscore for tuple argument name:<br>
<br>
.filter { (_: (name, age)) in age &gt;= 18 }<br>
<br>
<br>
3. (2) + allow to omit parenthesis (probably only in case of just one tuple argument)<br>
<br>
.filter { _: (name, age) in age &gt;= 18 }<br>
<br>
<br>
4. Use pattern matching syntax:<br>
<br>
.filter { case let (name, age) in age &gt;= 18 }<br>
<br>
(looks similar as allowed today: if case let (name, age) = x { print(name, age) }  )<br>
<br>
<br>
5. Use two pairs of parenthesis :<br>
<br>
.filter { ((name, age)) in age &gt;= 18 }<br>
<br>
Btw, about the 5th variant. If took what is allowed today:<br>
.filter { (arg: (name: String, age: Int)) in arg.age &gt;= 18 }<br>
, and allow type inference for tuple part arguments, we&#39;ll have this:<br>
.filter { (arg: (name, age)) in arg.age &gt;= 18 }<br>
, and if additionally allow skipping of tuple argument declaration we&#39;ll have:<br>
.filter { ((name, age)) in arg.age &gt;= 18 }<br>
I.e. two pairs for parenthesis for tuple destructuring, and such syntax is similar to the type this closure should have : ((String, Int)) -&gt; Bool<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<br>
<br>
On Thursday, June 1, 2017 12:25 PM, Vladimir.S via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br>
<br>
<br>
On 01.06.2017 0:42, John McCall wrote:<br></span><span class="">
 &gt;&gt; On May 31, 2017, at 2:02 PM, Stephen Celis &lt;<a href="mailto:stephen.celis@gmail.com" target="_blank">stephen.celis@gmail.com</a> &lt;mailto:<a href="mailto:stephen.celis@gmail.com" target="_blank">stephen.celis@gmail.co<wbr>m</a>&gt;&gt; wrote:<br>
 &gt;&gt;&gt; On May 28, 2017, at 7:04 PM, John McCall via swift-evolution<br></span><div><div class="h5">
 &gt;&gt;&gt; &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.<wbr>org</a>&gt;&gt; wrote:<br>
 &gt;&gt;&gt;<br>
 &gt;&gt;&gt; Yes, I agree.  We need to add back tuple destructuring in closure parameter<br>
 &gt;&gt;&gt; lists because this is a serious usability regression.  If we&#39;re reluctant to<br>
 &gt;&gt;&gt; just &quot;do the right thing&quot; to handle the ambiguity of (a,b), we should at least<br>
 &gt;&gt;&gt; allow it via unambiguous syntax like ((a,b)).  I do think that we should just<br>
 &gt;&gt;&gt; &quot;do the right thing&quot;, however, with my biggest concern being whether there&#39;s<br>
 &gt;&gt;&gt; any reasonable way to achieve that in 4.0.<br>
 &gt;&gt;<br>
 &gt;&gt; Closure parameter lists are unfortunately only half of the equation here. This<br>
 &gt;&gt; change also regresses the usability of point-free expression.<br>
 &gt;<br>
 &gt; The consequences for point-free style were expected and cannot really be<br>
 &gt; eliminated without substantially weakening SE-0110.  Closure convenience seems to<br>
 &gt; me to be a much more serious regression.<br>
<br>
John, do you also want to say &quot;and without weakening SE-0066&quot;? Because, if I<br>
understand correctly, in this case:<br>
<br>
   func add(_ x: Int, _ y: Int) -&gt; Int {<br>
     return x + y<br>
   }<br>
<br>
   zip([1, 2, 3], [4, 5, 6]).map(add)<br>
<br>
.. we have a clear function type mismatch situation, when map() expects function of<br>
type ((Int, Int))-&gt;Int, but function of type (Int,Int)-&gt;Int is provided ? So probably<br>
the additional &#39;reason&#39; of the &#39;problem&#39; in this case is SE-0066, no?<br>
Or I don&#39;t understand the SE-0066 correctly..<br>
Do we want to allow implicit conversions between function type ((Int,Int))-&gt;Int and<br>
(Int,Int)-&gt;Int?<br>
<br>
Quote from SE-0066:<br>
---<br>
(Int, Int) -&gt; Int    // function from Int and Int to Int<br>
((Int, Int)) -&gt; Int  // function from tuple (Int, Int) to Int<br>
---<br>
<br>
During this discussion I see a wish of some group of developers to just return back<br>
tuple splatting for function/closure arguments, so they can freely send tuple to<br>
function/closure accepting a list of parameters(and probably vise-versa).<br>
Is it worth to follow SE-0066 and SE-0110 as is, i.e. disallow tuple deconstructing<br>
and then, as additive change improve the situation with tuple<br>
splatting/deconstructing later with separate big proposal?<br>
<br>
Btw, about the SE-0110 proposal. It was discussed, formally reviewed and accepted. I<br>
expect that its revision also should be formally proposed/reviewed/accepted to<br>
collect a wide range of opinions and thoughts, and attract the attention of<br>
developers in this list to the subject.<br>
<br>
<br>
Also, if we revisit SE-0110, will this code be allowed?:<br>
<br>
func foo(_ callback: ((Int,Int))-&gt;Void) {}<br>
let mycallback = {(x:Int, y:Int)-&gt;Void in }<br>
foo(mycallback)<br>
<br>
and<br>
<br>
func foo(_ callback: (Int,Int)-&gt;Void) {}<br>
let mycallback = {(x: (Int, Int))-&gt;Void in }<br>
foo(mycallback)<br>
<br>
If so, what will be result of this for both cases? :<br>
<br>
print(type(of:mycallback)) // (Int,Int)-&gt;Void or ((Int,Int))-&gt;Void<br>
<br>
If allowed, do we want to allow implicit conversion between types (Int,Int)-&gt;Void and<br>
((Int,Int))-&gt;Void in both directions?  (Hello tuple splatting?)<br>
<br>
<br>
 &gt;<br>
 &gt; John.<br>
 &gt;<br>
 &gt;<br>
 &gt;&gt;<br>
 &gt;&gt; func add(_ x: Int, _ y: Int) -&gt; Int { return x + y }<br>
 &gt;&gt;<br>
 &gt;&gt; zip([1, 2, 3], [4, 5, 6]).map(add)<br>
 &gt;&gt;<br>
 &gt;&gt; // error: nested tuple parameter &#39;(Int, Int)&#39; of function &#39;(((_.Element,<br>
 &gt;&gt; _.Element)) throws -&gt; _) throws -&gt; [_]&#39; does not support destructuring<br>
 &gt;&gt;<br>
 &gt;&gt; This may not be a common pattern in most projects, but we heavily use this style<br>
 &gt;&gt; in the Kickstarter app in our functional and FRP code. Definitely not the most<br>
 &gt;&gt; common coding pattern, but a very expressive one that we rely on.<br>
 &gt;&gt;<br>
 &gt;&gt; Our interim solution is a bunch of overloaded helpers, e.g.:<br>
 &gt;&gt;<br>
 &gt;&gt; func tupleUp&lt;A, B, C&gt;(_ f: (A, B) -&gt; C) -&gt; ((A, B)) -&gt; C { return }<br>
 &gt;&gt;<br>
 &gt;&gt; zip([1, 2, 3], [4, 5, 6]).map(tupleUp(add))<br>
 &gt;&gt;<br>
 &gt;&gt; Stephen<br>
 &gt;<br>
 &gt; .<br>
 &gt;<br>
______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
</div></div><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.<wbr>org</a>&gt;<br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
<br>
<br>
</blockquote><div class="HOEnZb"><div class="h5">
______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div>