<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 17, 2017, at 6:29 PM, Joe Groff <<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 17, 2017, at 4:25 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class=""><br class=""><br class="">Sent from my iPhone</div><div class=""><br class="">On Mar 17, 2017, at 6:09 PM, Joe Groff <<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 17, 2017, at 4:05 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="position: relative;" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class=""><br class=""><br class="">Sent from my iPad</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class=""><br class="">On Mar 17, 2017, at 5:38 PM, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 17, 2017, at 12:34 PM, David Hart via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; position: relative;"><span class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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; float: none; display: inline !important;">Sent off-list by mistake:</span><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;">Nice proposal. I have a few comments inline:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 17 Mar 2017, at 18:04, Michael LeHew via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;">Hi friendly swift-evolution folks,<div class=""><br class=""></div><div class="">The Foundation and Swift team would like for you to consider the following proposal:</div><div class=""><br class=""></div><div class="">Many thanks,</div><div class="">-Michael</div><div class=""><br class=""></div><div class=""><h1 id="toc_0" class="" style="-webkit-print-color-adjust: exact; margin: 0px 0px 10px; padding: 0px; -webkit-font-smoothing: antialiased; cursor: text; position: relative; font-size: 28px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">Smart KeyPaths: Better Key-Value Coding for Swift</h1><ul class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);"><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Proposal: SE-NNNN</li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Authors: <a href="https://github.com/Catfish-Man" class="" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196); margin-top: 0px;">David Smith</a>, <a href="https://github.com/mlehew" class="" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196);">Michael LeHew</a>, <a href="https://github.com/jckarter" class="" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196);">Joe Groff</a></li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Review Manager: TBD</li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Status: <strong class="" style="-webkit-print-color-adjust: exact; margin-top: 0px;">Awaiting Review</strong></li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Associated PRs:<ul class="" style="-webkit-print-color-adjust: exact; margin: 0px 0px 15px; padding-left: 30px;"><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;"><a href="https://github.com/apple/swift-evolution/pull/644" class="" style="-webkit-print-color-adjust: exact; color: rgb(65, 131, 196); margin-top: 0px;">#644</a></li></ul></li></ul><h2 id="toc_1" class="" style="-webkit-print-color-adjust: exact; margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: antialiased; cursor: text; position: relative; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">Introduction</h2><p class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">We propose a family of concrete <em class="" style="-webkit-print-color-adjust: exact;">Key Path</em> types that represent uninvoked references to properties that can be composed to form paths through many values and directly get/set their underlying values.</p><h2 id="toc_2" class="" style="-webkit-print-color-adjust: exact; margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: antialiased; cursor: text; position: relative; font-size: 24px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">Motivation</h2><h4 id="toc_3" class="" style="-webkit-print-color-adjust: exact; margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: antialiased; cursor: text; position: relative; font-size: 16px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">We Can Do Better than String</h4><p class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">On Darwin platforms Swift's existing <code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">#keyPath()</code> syntax provides a convenient way to safely <em class="" style="-webkit-print-color-adjust: exact;">refer</em> to properties. Unfortunately, once validated, the expression becomes a <code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">String</code> which has a number of important limitations:</p><ul class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; padding-left: 30px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);"><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Loss of type information (requiring awkward <code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">Any</code> APIs)</li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Unnecessarily slow to parse</li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Only applicable to <code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">NSObjects</code></li><li class="" style="-webkit-print-color-adjust: exact; margin: 0px;">Limited to Darwin platforms</li></ul><h4 id="toc_4" class="" style="-webkit-print-color-adjust: exact; margin: 20px 0px 10px; padding: 0px; -webkit-font-smoothing: antialiased; cursor: text; position: relative; font-size: 16px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">Use/Mention Distinctions</h4><p class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">While methods can be referred to without invoking them (<code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">let x = foo.bar</code> instead of <code class="" style="-webkit-print-color-adjust: exact; margin: 0px 2px; padding: 0px 5px; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">let x = foo.bar()</code>), this is not currently possible for properties and subscripts.</p><p class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">Making indirect references to a properties' concrete types also lets us expose metadata about the property, and in the future additional behaviors.</p></div></div></div></div></blockquote>What metadata is attached? How is it accessed? What future features are you thinking about?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">To begin with, you'd have limited ability to stringify a key path. Eventually we'd like to support other reflectiony things, including:</div><div class=""><br class=""></div><div class="">- Asking for the primary key paths a type supports</div><div class="">- Asking for a key by name or index</div><div class="">- Breaking a key path down by components</div><div class=""><br class=""></div><div class="">I also see key path objects as a good way of eventually addressing some of the design problems we ran up against with property behaviors (<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md</a> from last year), including the problem of what exactly a property behavior declaration *is* (a type? a protocol? a function-like thing? something completely new?), and the problem of handling "out-of-band" operations on a property beyond getting and setting, such as clearing a cached lazy value, registering for notifications on an observable property, and so on. I think it would be natural to express property behaviors as a user-defined key path type; the key path type can provide the get/set logic for the property as well as any other interesting operations the property supports. This answers the questions of both what behaviors look like (they're just types that conform to KeyPath) and how they extend properties with new actions (they're just methods of the key path value) fairly nicely.</div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class="">Very interesting! This sounds like it would enable a very nice design in a project I'm working on right now. I'm looking forward to seeing this take shape in the future.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; 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;" class="">It sounds like it wouldn't solve one use case I was hoping property behaviors might solve though. Sometimes we have a property that we would like to make a constant but cont because we can't set it until phase 2. I would really like to have some notion of a "phase 2 initialized constant" which would provide a much stronger guarantee than IUO does. There would be a very small window where a trap is possible between phase 1 and when it is set in phase 2. It would probably make more sense to actually think of this as phase 1.5 where all of these properties must be initialized to a non-nil value, but self can be used in the initializing expressions.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I think that kind of use case can be handled even by the previous property behaviors proposal, by having a behavior that presents a non-optional property that only allows initialization by being set once, and traps if gotten before being initialized.</div></div></div></blockquote><div class=""><br class=""></div>Didn't it require trapping if set more than once? And it didn't offer a way to require initialization during phase 2 did it?</div></div></blockquote></div><br class=""><div class="">Yes, but perfectly closing those holes requires a much more complex type system than we have. Perfect is the enemy of good, and I think trapping on misuse gets you the lion's share of the benefit, and would still be a massive improvement over IUO.</div></div></div></blockquote><div><br class=""></div><div>Yes, I agree that it would be a massive improvement. I just wish there was a way to solve this that didn’t require fancy type system stuff. We already have relatively complex initialization rules that exist outside the type system that track initialization. It would be nice if we could solve this using a small enhancement to those rules. For example, we could have some kind of attribute or access control that is only available for IUO properties that restricts the setter to only be available in the initializer and guarantees that it is set to non-nil on exit of init. Maybe it’s too much of a special case to do this, but it would be really cool to have this hole plugged.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">-Joe</div></div></div></blockquote></div><br class=""></body></html>