<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=""><div class="">Ah, quite ingenious, Susan!</div><div class=""><br class=""></div><div class="">And you made me realize that the only reason my no-operator-needed code didn’t compile is that I had <span style="font-family: Menlo; font-size: 11px; background-color: rgb(255, 255, 255);" class="">keypath</span> instead of <span style="font-family: Menlo; font-size: 11px; background-color: rgb(255, 255, 255);" class="">keyPath</span>. So it was indeed “Paul needs to go to sleep now” option, which I will now do. 🙄</div><div class=""><br class=""></div><div class="">P</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 7, 2017, at 11:34 PM, Susan Cheng <<a href="mailto:susan.doggie@gmail.com" class="">susan.doggie@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">this work,<div class=""><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162);" class="">prefix<span style="" class=""> </span>operator<span style="" class=""> *</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="color:rgb(186,45,162)" class="">prefix</span> <span style="color:rgb(186,45,162)" class="">func</span> *<Root, Value>(keyPath: <span style="color:rgb(112,61,170)" class="">KeyPath</span><<span style="color:rgb(79,129,135)" class="">Root</span>, <span style="color:rgb(79,129,135)" class="">Value</span>>) -> (<span style="color:rgb(79,129,135)" class="">Root</span>) -> <span style="color:rgb(79,129,135)" class="">Value</span> {</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> <span style="color:rgb(186,45,162)" class="">return</span> { $0[keyPath: keyPath] }</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class="">}</div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class="">[<span style="color:rgb(209,47,27)" class="">"Hello, World"</span>].<span style="color:rgb(62,30,129)" class="">map</span>(*\<span style="color:rgb(112,61,170)" class="">String</span>.count) <span style="color:rgb(0,132,0)" class="">// [12]</span></div></div><div class=""><span style="color:rgb(0,132,0)" class=""><br class=""></span></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">2017-06-08 12:19 GMT+08:00 Paul Cantrell via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span>:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class="">It should be possible to achieve Ruby-like generality in Swift with a protocol for “thing that can converted to a transform function.” That wouldn’t need a special & operator.</div><div class=""><br class=""></div><div class="">Here’s a sketch. This sketch doesn’t compile — maybe not enough of Swift 4 is there yet for it to work, or maybe I am missing something obvious and need to go to sleep now — but it’s close enough to suggest the approach:</div><div class=""><br class=""></div><div class=""><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;background-color:rgb(255,255,255)" class=""><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">public</span> <span style="color:#323e7d" class="">protocol</span> TransformConvertible { // or whatever you want to call it</div><div style="margin:0px;line-height:normal;color:rgb(50,62,125)" class=""><span style="" class=""> </span>associatedtype<span style="" class=""> From</span></div><div style="margin:0px;line-height:normal;color:rgb(50,62,125)" class=""><span style="" class=""> </span>associatedtype<span style="" class=""> To</span></div><div style="margin: 0px; line-height: normal; min-height: 13px;" class=""> <br class="m_2164541534149277173webkit-block-placeholder"></div><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">var</span> transform: (<span style="color:#587ea8" class="">From</span>) -> <span style="color:#587ea8" class="">To</span> { <span style="color:#323e7d" class="">get</span> }</div><div style="margin:0px;line-height:normal" class=""> }</div><div style="margin:0px;font-size:12px;line-height:normal;font-family:Helvetica;min-height:14px" class=""><br class=""></div><div style="margin:0px;line-height:normal;color:rgb(88,126,168)" class=""><span style="" class=""> </span><span style="color:#323e7d" class="">extension</span><span style="" class=""> </span>KeyPath<span style="" class="">: </span>TransformConvertible<span style="" class=""> {</span></div><div style="margin:0px;line-height:normal;color:rgb(50,62,125)" class=""><span style="" class=""> </span>public<span style="" class=""> </span>typealias<span style="" class=""> From = </span><span style="color:#587ea8" class="">Root</span></div><div style="margin:0px;line-height:normal;color:rgb(50,62,125)" class=""><span style="" class=""> </span>public<span style="" class=""> </span>typealias<span style="" class=""> To = </span><span style="color:#587ea8" class="">Value</span></div><div style="margin: 0px; line-height: normal; min-height: 13px;" class=""> <br class="m_2164541534149277173webkit-block-placeholder"></div><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">public</span> <span style="color:#323e7d" class="">var</span> transform: (<span style="color:#587ea8" class="">Root</span>) -> <span style="color:#587ea8" class="">Value</span> {</div><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">return</span> { $0[keypath: <span style="color:#323e7d" class="">self</span>] }</div><div style="margin:0px;line-height:normal" class=""> }</div><div style="margin:0px;line-height:normal" class=""> }</div><div style="margin:0px;font-size:12px;line-height:normal;font-family:Helvetica;min-height:14px" class=""><br class=""></div><div style="margin:0px;line-height:normal;color:rgb(50,62,125)" class=""><span style="" class=""> </span>extension<span style="" class=""> </span><span style="color:#587ea8" class="">Sequence</span><span style="" class=""> {</span></div><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">public</span> <span style="color:#323e7d" class="">func</span> map<T, U>(<span style="color:#323e7d" class="">_</span> transformSource: <span style="color:#587ea8" class="">U</span>) -> [<span style="color:#587ea8" class="">T</span>]</div><div style="margin:0px;line-height:normal;color:rgb(88,126,168)" class=""><span style="" class=""> </span><span style="color:#323e7d" class="">where</span><span style="" class=""> </span>U<span style="" class="">: </span>TransformConvertible<span style="" class="">,</span></div><div style="margin:0px;line-height:normal" class=""> <span style="color:rgb(88,126,168)" class="">U</span>.<span style="color:#587ea8" class="">From</span> == <span style="color:#587ea8" class="">Element</span>,</div><div style="margin:0px;line-height:normal" class=""> <span style="color:rgb(88,126,168)" class="">U</span>.<span style="color:#587ea8" class="">To</span> == <font color="#587ea8" class="">T </font>{</div><div style="margin:0px;line-height:normal" class=""> <span style="color:#323e7d" class="">return</span> <span style="color:#587ea8" class="">map</span>(transformSource.<span style="color:#587ea8" class="">transform</span>)</div><div style="margin:0px;line-height:normal" class=""> }</div><div style="margin:0px;line-height:normal" class=""> }</div><div class=""><br class=""></div></div></div><div class="">This seems a bit more ambitious, perhaps not suitable for this round of Swift evolution work. But I throw it out there at least to show that supporting <span style="font-family:Menlo;font-size:11px;background-color:rgb(255,255,255)" class="">people.map(\.<wbr class="">firstName)</span> today <b class="">would not preclude</b> a generic keypath → function mechanism in the future:</div><div class=""><br class=""></div><div class=""><ul class="m_2164541534149277173MailOutline"><li class="">A flavor of map that accepts a keypath today could be generalized to accept TransformConvertible in the future without breaking existing code.</li><li class="">When calling a function that doesn’t know how to work with TransformConvertible, you could use (Foo.bar).transform, no special operator needed.</li></ul></div><div class=""><br class=""></div><div class="">Cheers,</div><div class=""><br class=""></div><div class="">Paul</div><div class=""><br class=""></div><div class=""><div class="">P.S. Largely irrelevant Ruby aside: Ruby’s & is not a free-floating operator, but part of the method invocation syntax indicating that the following arg should be treated as a block. Ruby calls a to_proc method on whatever is in that position. Symbol implements to_proc by returning a lambda that calls the method named by the symbol on the lambda’s first arg. Very much the duck-typed version of TransformConvertible above.</div></div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 7, 2017, at 10:21 PM, Stephen Celis via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:</div><br class="m_2164541534149277173Apple-interchange-newline"><div class=""><div class="">-1<br class=""><br class="">A -1 from me may be surprising. I'm excited about key path composition and generic solutions, e.g. this experiment with lenses: <a href="https://twitter.com/stephencelis/status/863916921577758721" target="_blank" class="">https://twitter.com/<wbr class="">stephencelis/status/<wbr class="">863916921577758721</a><br class=""><br class="">But I'd prefer a reusable solution for converting key paths into functions.<br class=""><br class="">Heaven help me for this Rubyism, but a prefix "&" operator (or, maybe better yet, some implicit mechanism) could convert a key-path to a function that passes a root value to a key path...<br class=""><br class=""> people.map(&\.firstName)<br class=""><br class="">This way any function that takes a transformation from "whole" to "part" could take a key path. Requiring an overload per instance is less flexible.<br class=""><br class="">Stephen<br class=""><br class=""><blockquote type="cite" class="">On Jun 7, 2017, at 10:58 PM, Tony Allevato via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class="">+1, I really like this. It would also align nicely with the method type flattening in SE-0042 (once it gets implemented), because passing keypaths (i.e., unbound property references) and unbound parameterless method references to map/flatMap would look nearly the same:<br class=""><br class="">```<br class="">struct Person {<br class=""> let firstName: String<br class=""> let lastName: String<br class=""> func fullName() -> String { return "\(firstName) \(lastName)" }<br class="">}<br class=""><br class="">let people: [Person]<br class="">let firstNames = people.map(\.firstName)<br class="">let fullNames = people.map(Person.fullName) // because after SE-0042, this will be (Person) -> String, not (Person) -> () -> String<br class="">```<br class=""><br class="">Especially if there's a move in the future to also use \. to denote unbound methods references, which was discussed during the keypath reviews. (Even with that, I believe it would be more work though to get rid of the explicit type name in the function case.)<br class=""><br class=""><br class="">On Wed, Jun 7, 2017 at 6:11 PM Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">+1. Would think that all variants should exist on Optional too unless it would be harmful.<br class="">On Wed, Jun 7, 2017 at 20:13 Michael J LeHew Jr via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">This is a great idea, and ought to be easy enough to bring forward! +1 from me!<br class=""><br class="">-Michael<br class=""><br class=""><blockquote type="cite" class="">On Jun 7, 2017, at 11:18 AM, Matt Diephouse via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class="">💯<br class=""><br class=""><blockquote type="cite" class="">On Jun 7, 2017, at 10:35 AM, Adam Sharp via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class="">The new smart key path feature is really lovely, and feels like a great addition to Swift.<br class=""><br class="">It seems like it might be straightforward to add overloads of `map` and `flatMap` to the standard library to make use of the new functionality:<br class=""><br class=""> let managers = flatOrganisation.managers<br class=""> let allEmployees = Set(managers.flatMap(\.<wbr class="">directReports))<br class=""> let employeeNames = Set(allEmployees.map(\.name))<br class=""><br class="">This feels like a really natural way of working with key paths in a functional style. It makes a lot of sense for collections, and possibly for Optional too (although as far as I can see optional chaining is more or less equivalent, and with more compact syntax).<br class=""><br class="">I’m hoping that this might be low-hanging fruit that could be considered for the Swift 4 release. I’d be happy to have a go at writing a proposal if there’s interest!<br class=""><br class="">–Adam<br class=""><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></blockquote><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></blockquote><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></blockquote><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></div></div></blockquote></div><br class=""></div><br class="">______________________________<wbr class="">_________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="">
<br class=""></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></body></html>