[swift-evolution] Draft proposal: multi-property assignment .= operator

Michel Fortin michel.fortin at michelf.ca
Mon Jan 11 07:40:28 CST 2016


Le 10 janv. 2016 à 22:29, Douglas Gregor <dgregor at apple.com> a écrit :
> 
>> On Jan 10, 2016, at 12:21 PM, Michel Fortin via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> (This proposal came from thinking about the memberwise initializer proposal as well as older proposals for "cascading" and creating scopes making some members act like local variables.)
>> 
>> I'd like to propose a syntax to set multiple properties at once. It would look like this:
>> 
>> 	var object = MyObject()
>> 	object .= (
>> 		property1: 1,
>> 		property2: "a"
>> 	)
>> 
>> and be equivalent to this:
>> 
>> 	var object = MyObject()
>> 	object.property1 = 1
>> 	object.property2 = "a"
>> 	
>> What the `.=` operator does is take each value in the tuple on the right and assign them to the property of the same name on the variable on the left. Assignments are performed in the same order as they're defined in the tuple.
> 
> For me, the scale of the problem isn’t large enough to warrant a language feature, especially given that...
> 
>> ## Tentative Implementation
>> 
>> It's almost possible already to implement this with reflection. Here's an attempt (using a different operator name because `.=` doesn't work as a custom operator):
>> 
>> 	infix operator ~= {  }
>> 
>> 	func ~= <T>(inout target: T, values: (a: Int, b: String)) {
>> 		let valuesMirror = Mirror(reflecting: values)
>> 		let targetMirror = Mirror(reflecting: target)
>> 		valueLoop: for valueField in valuesMirror.children {
>> 			guard let label = valueField.label else {
>> 				fatalError("Missing label in value tuple.")
>> 			}
>> 			for targetField in targetMirror.children {
>> 				print(targetField)
>> 				if targetField.label == label {
>> 					targetField.value = valueField.value
>> 					continue valueLoop
>> 				}
>> 			}
>> 		}
>> 	}
>> 
>> This fails because you can't assign to fields using the Mirror API. If this line could be replaced by something that works:
>> 
>> 	targetField.value = valueField.value
>> 
>> then we could have a library implementation.
> 
> Assigning to fields using the Mirror API is a completely reasonable feature to add.

If it can be done using purely library implementation, that's fine too. I have doubts you can make everything that should be a compile-time error if going that route (notice the runtime fatal error above), or get decent auto-completion. For that, we'd have to write a generic constraint that all the properties on the right exists on the left hand side with a compatible type, which is not expressible currently (as far as I know).

That said, I also realize now that the Mirror API does not do what I need here. I don't want to access "fields" (aka. stored properties) of the target object, I need to access all the user-exposed properties having the proper visibility in the current context, which includes computed properties that have a setter. Mirror is good for walking the tuple, but not the target.

-- 
Michel Fortin
https://michelf.ca



More information about the swift-evolution mailing list