[swift-evolution] Property Selectors

Joe Groff jgroff at apple.com
Mon Mar 20 11:45:15 CDT 2017


> On Mar 19, 2017, at 6:25 PM, Andrew Thompson <mrwerdo331 at me.com> wrote:
> 
> Opps, should have sent this to the mailing list….
> 
> That sounds pretty good. 😊 I find the response from the community to this proposal to be pretty cool.
> 
> 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.

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.

-Joe

> For example, consider the following:
> 
> We have a protocol, JSONEncodable, and a bunch of types that conform to it, namely `Int`, `String`, and `Data`.
> 
> 	protocol JSONEncodable {
> 		func encode() -> String
> 	}
> 
> 	extension Int {
> 		func encode() -> String { … }
> 	}
> 	
> 	// similarly for String and Data.
> 
> A very common scenario that occurs is composing a type where all properties conform to a particular protocol, for example:
> 
> 	struct Person {
> 		var age: Int
> 		var name: String
> 		var identifier: Data
> 	}
> 
> Now, we want to have `Person` conform to `JSONEncodable`, so we could just implement the encode method ourselves:
> 
> 	extension Person: JSONEncodable {
> 		func encode() -> String {
> 			return age.encode() + name.encode() + identifier.encode()
> 		}
> 	}
> 
> But this seems a little bit repetitive, what we really want is for the library author to declare the following:
> 
> 	For every type T whose properties conform to protocol P, we can derive a free conformance to protocol P for type T.
> 
> Applying this, we get the following code:
> 
> 	extension JSONEncodable where Self.InstanceProperties: JSONEncodable {
> 		func encode() -> String {
> 			let properties = Metatype<Self>.properties
> 			var output = “”
> 			for p in properties {
> 				output += p.read(self).encode()
> 			}
> 			return output
> 		}
> 	}
> 
> Now all a user needs to do is say that want to conform to the protocol:
> 
> 	struct Person: JSONEncodable {
> 		var age: Int
> 		var name: String
> 		var identifier: Data
> 	}
> 
> Cheers,
> - Andrew
> 
>> On 18 Mar 2017, at 6:08 am, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>> 
>>> 
>>> On Mar 14, 2017, at 1:02 AM, Andrew Thompson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> Hello Swift Evolution Community,
>>> 
>>> I’ve been thinking about a new language feature that would allow properties to be first class citizens. The basic idea is as follows:
>>> 
>>> 	let x: PropertySelector<UIView, CGFloat> = #property(UIView.frame.origin.x)
>>> 	let view: UIView = …
>>> 	view.frame.origin.x = 20
>>> 	x.read(view) // returns 20
>>> 	x.write(view, value: 9091)
>>> 	view.frame.origin.x // now 9091
>>> 
>>> 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):
>>> 
>>> 	func animate(view: UIView, property: PropertySelector<UIView, CGFloat>, amount: Int) {
>>> 		let originalValue = property.read(view)
>>> 		func generateKeyFrames() {
>>> 			let step = 1.0 / Double(amount)
>>> 			for i in 0..<amount {
>>> 				let newValue = originalValue + CGFloat(i)
>>> 				let time = Double(i) / Double(amount)
>>> 				UIView.addKeyframe(withRelativeStartTime: time,
>>> 								  relativeDuration: step,
>>> 								  animations: { property.write(view, value: newValue) }
>>> 				)
>>> 			}
>>> 		}
>>> 		
>>> 		UIView.animateKeyframes(withDuration: 1.0,
>>> 							   delay: 0,
>>> 							   options: [],
>>> 							   animations: generateKeyFrames,
>>> 							   completion: nil)
>>> 	}
>>> 
>>> 	let myView: UIView = …
>>> 	myView.frame = CGRect(x: 20, y: 100, width: 99, height: 120)
>>> 
>>> 	// once this completes, myView.frame.origin.x == 120
>>> 	animate(view: myView, property: #property(UIView.frame.origin.x), amount: 100)
>>> 	
>>> 	// once this completes, myView.frame.size.width == 198
>>> 	animate(view: myView, property: #property(UIView.frame.size.width), amount: 99)
>>> 
>>> I think this would be a pretty neat feature to have, what do you think?
>> 
>> We agree! How does this sound:
>> 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170313/033998.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170313/033998.html>
>> 
>> -Joe
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170320/ba8c21a0/attachment.html>


More information about the swift-evolution mailing list