<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 19, 2017, at 6:25 PM, Andrew Thompson <<a href="mailto:mrwerdo331@me.com" class="">mrwerdo331@me.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Opps, should have sent this to the mailing list….</div><div class=""><br class=""></div><div class="">That sounds pretty good. 😊 I find the response from the community to this proposal to be pretty cool.<div class=""><div class=""><br class=""></div><div class="">While reading some of the discussion around your proposal, I’ve seen requests where people are wanting to retrieve the list of an object’s properties. I think this is an interesting idea to explore, particularly if it was possible to generalise about all of the properties stored on an object.</div></div></div></div></div></blockquote><div><br class=""></div><div>I agree, I think that's a natural extension of the core key path functionality. We're trying to keep the initial work small in scope to begin with, but I think it's a good foundation to start building out a better reflection model.</div><div><br class=""></div><div>-Joe</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=""><div class=""><div class="">For example, consider the following:</div><div class=""><br class=""></div><div class="">We have a protocol, JSONEncodable, and a bunch of types that conform to it, namely `Int`, `String`, and `Data`.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>protocol JSONEncodable {<br class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode() -> String<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Int {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode() -> String { … }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// similarly for String and Data.</div><div class=""><br class=""></div><div class="">A very common scenario that occurs is composing a type where all properties conform to a particular protocol, for example:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>struct Person {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var age: Int</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var name: String</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var identifier: Data</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Now, we want to have `Person` conform to `JSONEncodable`, so we could just implement the encode method ourselves:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Person: JSONEncodable {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode() -> String {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return age.encode() + name.encode() + identifier.encode()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">But this seems a little bit repetitive, what we really want is for the library author to declare the following:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>For every type T whose properties conform to protocol P, we can derive a free conformance to protocol P for type T.</div><div class=""><br class=""></div><div class="">Applying this, we get the following code:</div><div class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension JSONEncodable where Self.InstanceProperties: JSONEncodable {<br class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode() -> String {<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>let properties = Metatype<Self>.properties<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>var output = “”<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>for p in properties {<br class=""><span class="Apple-tab-span" style="white-space: pre;">                                </span>output += p.read(self).encode()<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return output<br class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Now all a user needs to do is say that want to conform to the protocol:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>struct Person: JSONEncodable {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var age: Int</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var name: String</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var identifier: Data</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Cheers,</div><div class="">- Andrew</div></div></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 18 Mar 2017, at 6:08 am, Joe Groff <<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div 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=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Mar 14, 2017, at 1:02 AM, Andrew Thompson 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="">Hello Swift Evolution Community,<br class=""><br class="">I’ve been thinking about a new language feature that would allow properties to be first class citizens. The basic idea is as follows:<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>let x: PropertySelector<UIView, CGFloat> = #property(UIView.frame.origin.x)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>let view: UIView = …<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>view.frame.origin.x = 20<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>x.read(view) // returns 20<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>x.write(view, value: 9091)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>view.frame.origin.x // now 9091<br class=""><br class="">This is a trivial example, but now we can do more interesting things in our code. For example, we can animate any property on a view (that is documented to be animatable of course):<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>func animate(view: UIView, property: PropertySelector<UIView, CGFloat>, amount: Int) {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>let originalValue = property.read(view)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>func generateKeyFrames() {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>let step = 1.0 / Double(amount)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>for i in 0..<amount {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>let newValue = originalValue + CGFloat(i)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>let time = Double(i) / Double(amount)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>UIView.addKeyframe(withRelativeStartTime: time,<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> relativeDuration: step,<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> animations: { property.write(view, value: newValue) }<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span>UIView.animateKeyframes(withDuration: 1.0,<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> delay: 0,<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> options: [],<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> animations: generateKeyFrames,<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-converted-space"> </span> completion: nil)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>let myView: UIView = …<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>myView.frame = CGRect(x: 20, y: 100, width: 99, height: 120)<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// once this completes, myView.frame.origin.x == 120<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>animate(view: myView, property: #property(UIView.frame.origin.x), amount: 100)<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// once this completes, myView.frame.size.width == 198<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>animate(view: myView, property: #property(UIView.frame.size.width), amount: 99)<br class=""><br class="">I think this would be a pretty neat feature to have, what do you think?<br class=""></div></div></blockquote></div><br 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;"><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;">We agree! How does this sound:</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><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;"><a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170313/033998.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170313/033998.html</a></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><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;">-Joe</div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>