<div><br><div class="gmail_quote"><div>On Wed, Jun 7, 2017 at 14:33 Gwendal Roué via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div>Le 7 juin 2017 à 17:15, Vladimir.S &lt;<a href="mailto:svabox@gmail.com" target="_blank">svabox@gmail.com</a>&gt; a écrit :</div><br class="m_-2576005043248980472Apple-interchange-newline"><div><div>On 07.06.2017 16:20, Gwendal Roué wrote:<br><blockquote type="cite"><blockquote type="cite">Le 7 juin 2017 à 15:11, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a> &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">mailto:xiaodi.wu@gmail.com</a>&gt;&gt; a écrit :<br><br>While SE-0025 was generally regarded as unfortunate, the thousands of emails that followed relitigating it were much, much worse.<br><br>The removal of implicit tuple splatting, which is *not* SE-0110, was approved on the understanding that it would be a regression until explicit tuple splatting is introduced. This tradeoff was considered and approved. It’s clear that you disagree, but that is not grounds to divert a necessary discussion on mitigating SE-0110 into relitigating something else.<br></blockquote>Push me out if you want, but will you push out those blatant wounds out as well?<br>Example 1<br>-        return columns.index { (column, _) in column.lowercased() == lowercaseName }<br>+        return columns.index { $0.0.lowercased() == lowercaseName }<br></blockquote><br>Why not<br>columns.index { (arg: (column: String, _: Int)) in arg.column.lowercased() == lowercaseName }<br>?<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>It would works, but it&#39;s less than ideal: the `args` name has no meaning. We have an extra type declaration instead of type inference. It&#39;s much longer. The clarity is tremendously reduced.</div></div><div style="word-wrap:break-word"><div><br></div><div>- return columns.index { (column, _) in column.lowercased() == lowercaseName }</div></div><div style="word-wrap:break-word"><div><div>+ return columns.index { (arg: (column: String, _)) in arg.column.lowercased() == lowercaseName }</div></div><div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>Yes, I understand that first syntax short and not verbose, but the alternative you provided IMHO much worse than explicit type declaration in closure.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>It&#39;s not an &quot;alternative&quot;: it&#39;s Swift 3.</div><div><br></div><div>Maybe you did already profit from it, but did not notice.</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div><br><blockquote type="cite">Example 2 :<br>-            .map { (mappedColumn, baseColumn) -&gt; (Int, String) in<br>+            .map { (pair) -&gt; (Int, String) in<br>+                let mappedColumn = pair.key<br>+                let baseColumn = pair.value<br></blockquote><br>Can&#39;t compile something like this even in Swift 3, could you provide a small code snippet for this?<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>Sure:</div><div><br></div><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures;color:#ba2da2">    let</span><span style="font-variant-ligatures:no-common-ligatures"> mapping: [</span><span style="font-variant-ligatures:no-common-ligatures;color:#703daa">String</span><span style="font-variant-ligatures:no-common-ligatures">: </span><span style="font-variant-ligatures:no-common-ligatures;color:#703daa">String</span><span style="font-variant-ligatures:no-common-ligatures">] = ...</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">    mapping</span><span style="font-variant-ligatures:no-common-ligatures">.map { (mappedColumn, baseColumn) -&gt; (</span><span style="font-variant-ligatures:no-common-ligatures;color:rgb(112,61,170)">Int</span><span style="font-variant-ligatures:no-common-ligatures">, </span><span style="font-variant-ligatures:no-common-ligatures;color:rgb(112,61,170)">String</span><span style="font-variant-ligatures:no-common-ligatures">) </span><span style="font-variant-ligatures:no-common-ligatures;color:rgb(186,45,162)">in ... }</span></div></div></div><div style="word-wrap:break-word"><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures;color:rgb(186,45,162)"><br></span></div><blockquote type="cite"><div><div><blockquote type="cite">Example 3 :<br>-                .map { (table, columns) in &quot;\(table)(\(columns.sorted().joined(separator: &quot;, &quot;)))&quot; }<br>+                .map { &quot;\($0.key)(\($0.value.sorted().joined(separator: &quot;, &quot;)))&quot; }<br></blockquote><br>Same, why not<br><br>.map { (arg: (table: String, columns: [String])) in &quot;\(arg.table)(\(arg.columns.sorted().joined(separator: &quot;, &quot;)))&quot; }<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>Same answer: the extra `args` works, but we still have an ergonomics regression from Swift 3.</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div><blockquote type="cite">Example 4 :<br>-                dictionary.first { (column, value) in column.lowercased() == orderedColumn.lowercased() }<br>+                dictionary.first { $0.key.lowercased() == orderedColumn.lowercased() }<br></blockquote><br>Same.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>Indeed.</div><div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div><br><blockquote type="cite">See also messages from Stephen Cellis, who shows how other kinds of developer code has lost expressivity and clarity with those changes that have been &quot;considered and approved&quot;.<br></blockquote><br>Gwendal, no one saying that new syntax is better, that it is good thing that we lost the short syntax for tuple argumment deconstructions in closures.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>Good to hear :-)</div><div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>But there is just no easy/obvious way to keep that syntax in Swift 4. The problem can&#39;t be solved just by not implementing SE-0110, as in Swift4 we should have two separate function types: one that takes single tuple argument and second that accepts a list of arguments, i.e. (Int,Int)-&gt;() and ((Int,Int))-&gt;() should be two different types now.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>Of course I understand that.</div><div><br></div><div>I expect the compiler to perform the expected conversions for ergonomics&#39; sake.</div><div><br></div><div>I can understand that this sugar could be added *after* current problems which are not related to ergonomics are solved. I just want to make it clear that there is an ergonomics problem *now*, and that solving it should have a very high priority.</div></div></div></blockquote><div><br></div><div>If this was the point you wished to make, then there isn’t any disagreement, I don’t think. We *all* can obviously agree that there is a loss in ergonomics due to SE-0110.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div>This is not just SE-0110, this is also SE-0066, so, to be correct, you should propose to revisit it also.<br><br>Please look here:<br><br>func foo(_ x: Int, _ y: Int) {} // type(of: foo) should be (Int, Int)-&gt;()<br>func bar(_ x (Int, Int)) {} // type(of: bar) should be ((Int, Int))-&gt;()<br><br>The above is described in SE-0066. Then, you have a closure constants:<br><br>var fooClosure = {(x: Int, y: Int) in }<br>var barClosure = {(x: (Int, Int)) in }<br><br>what should be types of these closures? Obvious the same: (Int,Int)-&gt;() and ((Int,Int))-&gt;() respectively.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>I guess you mean, not the same: (Int, Int) -&gt; () vs. ((Int, Int)) -&gt; ().</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>Then you have a func that accepts ((Int,Int))-&gt;Int closure:<br><br>func schedule(callback: ((Int,Int))-&gt;()) {..}<br><br>, given type of foo func is (Int, Int)-&gt;() , do you suggest to allow sending foo to &#39;schedule&#39; func? The same question is for fooClosure<br><br>schedule(callback: foo) // ??<br>schedule(callback: fooClosure) // ??<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>Yes, I do. For ergonomics&#39; sake.</div><div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>Probably we can(if technically possible, I don&#39;t know) to always allow sending of function/closure with list of arguments when function with one tuple is required. I don&#39;t know how such exceptional rule would looks like inside type system of Swift, what should be result of &#39;foo is ((Int,Int))-&gt;()&#39; then and &#39;type(of:foo) == type(of:bar)&#39; in such case.<br>But this requires a formal proposal, review period and implementation(as I understand, better before Swift 4 release). Probably you can submit such proposal, go through the review period and help with implementation.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>Seriously I don&#39;t know if I have the skills to write such a proposal. It dives much too deep in the compiler internals for me to be efficient in the proposal process.</div><div><br></div><div>I thus hope that I did succeed showing how seriously bad are the regressions induced by SE-0110, and that a skilled language designer will sponsor an ergonomics-rescue proposal.</div><div><br></div><div>So far, the answer to the ergonomics regression reports have been much too often negative. I wish ergonomics had better support in the community. Very few regular developers talk here, unfortunately.</div></div></div></blockquote><div><br></div><div>As I mentioned in a reply above, re-reading SE-0029 gives a full account of the rationale for this series of proposals. It acknowledges that tuple splatting is useful and explicitly welcomes a complete design for future consideration. However, it states that this is *hard*, and that the reason for not having one is precisely what you said: no one with both the expertise and the time has stepped forward to do it. Again, I’m not sure we’re covering new ground here, or even disagreeing.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div>In this case we&#39;ll have the same user-friendly closure/function parameters expirience but with respect to correct function types.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>That would be just great!</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite">But currently we have a situation: argument of type ((Int,Int))-&gt;() is required, and we provide argument of another type : (Int,Int)-&gt;() i.e. incorrect type.<br></blockquote><blockquote type="cite"><div><div>The only obvious solution here is using the common rule for type mismatch - disallow this.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>And the obvious and easy way leads to regressions.</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>Currently we have a number of suggestions how we can improve usability for the discussed problem:<br><br>* use &#39;let&#39; syntax in closure argument list to deconstruct tuple argument<br><br>* use doubled parenthesis to deconstruct tuple argument: { ((key, value)) in .. }<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>Both &#39;let&#39; and doubled parenthesis fail in ergonomics.</div><div><br></div><div>Let me explain you why: when you provide a closure to a function, do you know if the function expects a single-tuple input, or a multiple-arguments input? You don&#39;t know.</div></div></div></blockquote><div><br></div><div>Wait, why don’t you know? This is a baffling statement for me. Of course you would know, by inspection, surely?</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div></div><div>For example, take those three functions:</div><div><br></div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>func f(_ closure:(Int, Int) -&gt; ())</div><div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>func g(_ closure:((Int, Int)) -&gt; ())</div><div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>func h(_ closure:((a: Int, b: Int)) -&gt; ())</div><div><br></div><div>If one can always write (as in Swift 3):</div><div><br></div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>f { (a, b) in ... }</div><div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>g { (a, b) in ... }</div></div><div><div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>c { (a, b) in ... }</div></div></div><div><br></div><div>Then one can easily deal with a badly fit closure signature.</div><div><br></div><div>This is most examplified by dictionaries. They always expose (key: Key, value: Value) tuples (their Element type). Problem is that &#39;key&#39; and &#39;value&#39; are identifiers that only matter for dictionaries, not for dictionary users. It&#39;s very important for dictionary users to forget about tuples, and the `key` and `value` words:</div><div><br></div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>// No pollution</div><div><span class="m_-2576005043248980472Apple-tab-span" style="white-space:pre-wrap">        </span>dictionary.map { (name, score) in ... }</div><div><br></div><div>That wish (let one easily deal with a badly fit closure signature) is also asked by Stephen Cellis in his functional explorations.</div></div></div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div>* generation of closure of correct type if closure is declared inside function call and arguments have no type annotations, i.e.<br>  //schedule(callback: foo) // disallowed, type mismatch<br>  //schedule(callback: fooClosure) // disallowed, type mismatch<br><br>  // allowed. compiler will generate closure of type ((Int,Int))-&gt;() from this code<br>  schedule { x,y in }<br><br>  // type mismatch, this syntax defines closure of (Int,Int)-&gt;() type<br>  //schedule { (x: Int, y: Int) in }<br><br>But because all of this are additional features that can be added later, and each required to be reviewed/discussed in details, core team can decide to delay such &#39;fix&#39; for after-release period. Let&#39;s wait and see what core team had to say about this subject.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div>I can&#39;t wait to hear from the core team.</div></div><div style="word-wrap:break-word"><div><br></div><div>Gwendal</div><div><br></div></div>_______________________________________________<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/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div>