<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Great catch! I didn’t know that was possible! I’ll add it to the proposal. Thanks!<div class=""><div class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""></div></div></div></div><div class="">
<div style="color: rgb(0, 0, 0); letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">- Dennis</div></div>
</div>
<br class=""><div><blockquote type="cite" class=""><div class="">On May 30, 2016, at 3:53 PM, Vladimir.S <<a href="mailto:svabox@gmail.com" class="">svabox@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">I believe you should add currently available syntax to proposal text:<br class=""><br class="">let c = zip(a,b).reduce(0) { (acc, tuple: (a: Int, b: Int)) in<br class=""> acc + tuple.a + tuple.b<br class="">}<br class=""><br class="">func takesATuple(tuple : (valueA: Int, valueB: Int)) {<br class=""> print("a: \(tuple.valueA) b:\(tuple.valueB)")<br class="">}<br class=""><br class="">Not so nice as proposed, but not so ugly as just tuple.0.<br class="">I'm not sure if the proposed feature is adding important improvement to the language.<br class=""><br class="">On 30.05.2016 0:20, Dennis Weissmann via swift-evolution wrote:<br class=""><blockquote type="cite" class="">Thanks for everyone participating in this discussion! :)<br class="">I’ve drafted a formal proposal, it is available<br class="">here: <a href="https://github.com/dennisweissmann/swift-evolution/blob/tuple-destructuring/proposals/0000-tuple-destructuring.md" class="">https://github.com/dennisweissmann/swift-evolution/blob/tuple-destructuring/proposals/0000-tuple-destructuring.md</a><br class=""><br class="">Please let me know what you think (it would be great if a native speaker<br class="">could take a look at grammar and spelling mistakes). Thanks!<br class=""><br class=""><br class=""> Tuple Destructuring in Parameter Lists<br class=""><br class=""> * Proposal: SE-NNNN<br class=""> <<a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md</a>><br class=""> * Author(s): Dennis Weissmann <<a href="https://github.com/dennisweissmann" class="">https://github.com/dennisweissmann</a>><br class=""> * Status: *Awaiting review*<br class=""> * Review manager: TBD<br class=""><br class=""><br class=""> Introduction<br class=""><br class="">Tuple destructuring is the process of extracting elements from tuples.<br class=""><br class="">This is valid today:<br class=""><br class="">Swift<br class=""><br class="">|let point = (x: 20.0, y: 31.0, z: 42.0) // Approach 1: let x = point.x let<br class="">y = point.y let z = point.z // Approach 2: let (x, y, z) = point // For-in<br class="">loops support tuple destructuring for (x, y, z) in [point] { // use x, y, z }|<br class=""><br class="">Swift-evolution thread: [Pitch] Tuple Destructuring in Parameter Lists<br class=""><<a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/16190" class="">http://thread.gmane.org/gmane.comp.lang.swift.evolution/16190</a>><br class=""><br class=""><br class=""> Motivation<br class=""><br class="">This proposal seeks to generalize this behavior for every use case where<br class="">tuples need to be destructured. These are parameter lists in closures and<br class="">parameter lists in functions. Consistency is a major goal of Swift but it<br class="">is currently only possible to destructure tuples in the above mentioned places.<br class=""><br class=""><br class=""> Proposed solution<br class=""><br class="">Extending tuple destructuring to parameter lists seems natural and improves<br class="">consistency in the language.<br class=""><br class=""><br class=""> Closures<br class=""><br class="">Parameters in closures are currently not directly destructable. They can<br class="">either be accessed via |.0|, |.1|, etc. or can be destructured by assigning<br class="">them to variables in an explicit statement.<br class=""><br class="">It feels natural to do this right in the parameter list itself (just like<br class="">with for-in loops).<br class=""><br class="">Swift<br class=""><br class="">|let a = [0,1,2,3,4,5,6,7,8,9] let b = [0,1,2,3,4,5,6,7,8,9] // Allowed<br class="">today: let c = zip(a,b).reduce(0) { acc, tuple in acc + tuple.0 + tuple.1 }<br class="">// Also allowed today: let c = zip(a,b).reduce(0) { acc, tuple in let<br class="">(valueA, valueB) = tuple return acc + valueA + valueB } // Proposed syntax:<br class="">let c = zip(a,b).reduce(0) { acc, (valueA, valueB) in acc + valueA + valueB }|<br class=""><br class=""><br class=""> Functions<br class=""><br class="">When it comes to functions this proposal uses Swift's feature of<br class="">differentiating between internal and external parameter names.<br class=""><br class="">Swift<br class=""><br class="">|// Allowed today: func takesATuple(tuple: (Int, Int)) { let valueA =<br class="">tuple.0 let valueB = tuple.1 // ... } // Proposed syntax: func<br class="">takesATuple(tuple (valueA, valueB): (Int, Int)) { // use valueA // use<br class="">valueB }|<br class=""><br class="">This design has no visible effects to the call site of a function but makes<br class="">it very convenient for the function author to use the tuple's elements<br class="">inside the function body.<br class=""><br class=""><br class=""> Impact on existing code<br class=""><br class="">This feature is strictly additive and does not effect current code.<br class=""><br class=""><br class=""> Alternatives considered<br class=""><br class="">Leave it as is destructure in a separate assignment.<br class=""><br class=""><br class=""><br class="">- Dennis<br class=""><br class=""><blockquote type="cite" class="">On May 11, 2016, at 10:12 AM, Dennis Weissmann via swift-evolution<br class=""><<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a> <<a href="mailto:swift-evolution@swift.org" class="">mailto:swift-evolution@swift.org</a>>> wrote:<br class=""><br class="">Thanks for all your feedback!<br class=""><br class="">This is the current statistic:<br class="">Closure syntax: All positive<br class="">Function syntax: 3 (or 4) positive, 2 negative<br class=""><br class="">I’ll try to address the concern Geordie and T.J. have.<br class=""><br class=""><blockquote type="cite" class="">func takesATuple(someInt: Int, tuple: (valueA: String, valueB: String)) {}<br class=""></blockquote><br class=""><blockquote type="cite" class="">It’s true that you still have the ‚overhead‘ of having to<br class="">type /tuple./ before accessing its members. But this is almost always<br class="">what I want (hopefully you’d never actually name your tuple ‚tuple‘,<br class="">instead it’d be a logical namespace for what it contains). Do you have a<br class="">real-world example where you’d need this? To me it seems that in a case<br class="">like this the API that produced the tuple would need refining rather<br class="">than the language itself.<br class=""></blockquote><br class="">What you suggest here is not tuple destructuring but using labeled<br class="">tuples. And while I’m totally with you that this is for many cases the<br class="">better approach, I still think we should introduce it to functions as<br class="">well, for consistency and readability reasons.<br class="">In the end inconsistency is what led to this thread because tuple<br class="">destructuring is already possible today - in for loops:<br class=""><br class="">letstringTuple = [("", "”), ("", "")]<br class="">for(i, j) instringTuple {}<br class=""><br class="">That made me wonder if it’s also possible for closures (because I needed<br class="">it there - and eventually someone will definitely wonder if it’s possible<br class="">for function arguments as well).<br class=""><br class="">You also asked me for my use case. To be honest, I don’t have one for the<br class="">function version, but imagine the following:<br class=""><br class="">My current closure use case is this<br class="">(template.points and resampledPoints are of type [CGPoint]):<br class=""><br class="">letlocalHighestSimilarity = zip(template.points,<br class="">resampledPoints).reduce(0.0) { accumulator, points in<br class=""> let(template, resampled) = points<br class=""> returnaccumulator + Double(template.x* resampled.x+ template.y*<br class="">resampled.y)<br class="">}<br class=""><br class="">To reuse this code elsewhere I maybe want to refactor the closure into a<br class="">function (using your labeled tuple suggestion):<br class=""><br class="">funcaccumulateSimilarity(accumulator: Double, for points: (point1:<br class="">CGPoint, point2: CGPoint)) -> Double{<br class=""> returnaccumulator + Double(points.point1.x* points.point2.x+<br class="">points.point1.y* points.point2.y)<br class="">}<br class=""><br class="">This isn’t particularity readable (image passing a CGRect and you need<br class="">the points or a more complex calculation). Compare it to this:<br class=""><br class="">funcaccumulateSimilarity(accumulator: Double, for (point1, point2):<br class="">(CGPoint, CGPoint)) -> Double{<br class=""> returnaccumulator + Double(point1.x * point2.x + point1.y * point2.y)<br class="">}<br class=""><br class="">You can of course still pass a named tuple instead of an unnamed, but it<br class="">doesn’t make any difference, which brings me to an aside*.<br class=""><br class="">I think the second approach makes the calculation much more<br class="">comprehensible and it just feels “intuitive” (again, at least for me) :).<br class=""><br class=""><br class="">- Dennis<br class=""><br class="">* I’m not sure how scientifically correct the following statement is but<br class="">strictly speaking (at least for me) (valueA: String, valueB: String) is<br class="">not of the same type as (String, String) just like func d(string: String,<br class="">int: Int) is different from func e(_: String, _: Int) though in Swift the<br class="">tuples are interchangeable (you can pass one where the other is expected).<br class=""><br class=""><blockquote type="cite" class="">On May 8, 2016, at 6:10 PM, Geordie J <<a href="mailto:geojay@gmail.com" class="">geojay@gmail.com</a><br class=""><<a href="mailto:geojay@gmail.com" class="">mailto:geojay@gmail.com</a>>> wrote:<br class=""><br class="">Comments below<br class=""><br class=""><blockquote type="cite" class="">Am 05.05.2016 um 20:22 schrieb Dennis Weissmann via swift-evolution<br class=""><<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a> <<a href="mailto:swift-evolution@swift.org" class="">mailto:swift-evolution@swift.org</a>>>:<br class=""><br class="">Following a short discussion with positive feedback on<br class="">[swift-users](<a href="http://thread.gmane.org/gmane.comp.lang.swift.user/1812" class="">http://thread.gmane.org/gmane.comp.lang.swift.user/1812</a>)<br class="">I’d like to discuss the following:<br class=""><br class="">Tuples should be destructible into their components in parameter lists.<br class=""><br class="">Consider the following code:<br class=""><br class="">let a = [0,1,2,3,4,5,6,7,8,9]<br class="">let b = [0,1,2,3,4,5,6,7,8,9]<br class=""><br class="">let c = zip(a,b).reduce(0) { acc, tuple in<br class=""> acc + tuple.0 + tuple.1<br class="">}<br class=""><br class="">tuple is of type (Int, Int).<br class=""><br class="">The problem is that the calculation is not very comprehensible due<br class="">to .0 and .1. That’s when destructuring tuples directly in the<br class="">parameter list comes into play:<br class=""><br class="">let c = zip(a,b).reduce(0) { acc, (valueA, valueB) in<br class=""> acc + valueA + valueB<br class="">}<br class=""></blockquote><br class="">+1 I think this is a great way to go about it.<br class=""><br class=""><blockquote type="cite" class=""><br class="">The above is what I propose should be accepted by the compiler (but<br class="">currently isn’t).<br class=""><br class="">Currently tuple destructuring is possible like this:<br class=""><br class="">let c = zip(a,b).reduce(0) { (acc, tuple) in<br class=""> let (valueA, valueB) = tuple<br class=""> return acc + valueA + valueB<br class="">}<br class=""><br class="">This is not about saving one line ;-). I just find it much more<br class="">intuitive to destructure the tuple in the parameter list itself.<br class=""></blockquote><br class="">Agreed<br class=""><br class=""><blockquote type="cite" class=""><br class="">The same thing could be done for functions:<br class=""><br class="">func takesATuple(someInt: Int, tuple: (String, String))<br class=""><br class="">Here we also need to destructure the tuple inside the function, but the<br class="">intuitive place (at least for me) to do this would be the parameter list.<br class=""><br class="">In the following example I'm making use of Swift’s feature to name<br class="">parameters different from their labels (for internal use inside the<br class="">function, this is not visible to consumers of the API):<br class=""><br class="">func takesATuple(someInt: Int, tuple (valueA, valueB): (String, String))<br class=""></blockquote><br class=""><br class="">I’m not such a fan of this though. I realize what I’m about to write<br class="">here is discussing a slightly different point but bear with me: I was<br class="">under the impression it was already possible to do something like this<br class="">(maybe only possible with typealiases):<br class=""><br class="">func takesATuple(someInt: Int, tuple: (valueA: String, valueB: String)) {}<br class=""><br class="">I find that syntax readable and extensible: you can make a type alias<br class="">for your tuple type '(valueA: String, valueB: String)‘, you can then use<br class="">it like this:<br class=""><br class="">func takesATuple(someInt: Int, tuple: MyAliasedTupleType) {<br class=""> print(tuple.valueA)<br class="">}<br class=""><br class="">It’s true that you still have the ‚overhead‘ of having to<br class="">type /tuple./ before accessing its members. But this is almost always<br class="">what I want (hopefully you’d never actually name your tuple ‚tuple‘,<br class="">instead it’d be a logical namespace for what it contains). Do you have a<br class="">real-world example where you’d need this? To me it seems that in a case<br class="">like this the API that produced the tuple would need refining rather<br class="">than the language itself.<br class=""><br class=""><blockquote type="cite" class=""><br class="">Here valueA and valueB would be directly usable within the function.<br class="">The tuple as a whole would not be available anymore.<br class=""><br class=""><br class="">Now it’s your turn!<br class=""><br class="">1. What do you think?<br class="">2. Is this worth being discussed now (i.e. is it implementable in the<br class="">Swift 3 timeframe) or should I delay it?<br class=""><br class="">Cheers,<br class=""><br class="">- Dennis<br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a> <<a href="mailto:swift-evolution@swift.org" class="">mailto:swift-evolution@swift.org</a>><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></blockquote></blockquote><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a> <<a href="mailto:swift-evolution@swift.org" class="">mailto:swift-evolution@swift.org</a>><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></blockquote><br class=""><br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""><br class=""></blockquote></div></div></blockquote></div><br class=""></body></html>