[swift-evolution] Proposal: Expose getter/setters in the same way as regular methods

Charles Srstka cocoadev at charlessoft.com
Sun Dec 27 13:20:54 CST 2015


> On Dec 27, 2015, at 4:23 AM, Tino Heth <2th at gmx.de> wrote:
> 
>> 
>> Of course, if you’re worried about the performance costs associated with that extra method call, you might want to include a keyword, such as “observable”, and only generate the method call(s) if that keyword is on the property.
> I strongly agree that Swift should have/keep a possibility to create properties with no performance penalty — but I guess comfort is more important, so I'd rather make observable the default and offer a possibility to disable it.
> 
> Tino

The problem, as I see it, is that KVO is not useful unless the author has specifically thought about it, and if “observable” is not the default, but something that the author of the class had to add, this demonstrates that the author *has* considered KVO compliance for the property.  Without some way to know that the property has deliberately been made KVO compliant, code that observes the property cannot be reliable. Therefore, I’d suggest *not* making observable the default, as it ultimately makes KVO a lot more useful.

Example:

class MyObject {
	var foo: Int { get } // This is a computed property, possibly dependent on something else. Can I safely observe it and expect it to work?

	var bar: Int           // This is a stored property—but do I know it won’t be changed to a computed property in the future? Can I observe this and trust my code won’t break in version 2.0?
}

vs.

class MyObject {
	observable var foo: Int { get } // YES I can safely observe this.

	observable var bar                 // YES I can safely observe this.
}

Observing things that aren’t observable is fraught with peril (in the current Objective-C implementation, it can often lead to crashes via exceptions being thrown). Knowing that it’s safe is valuable—I’d even say essential. Currently you have to look in the documentation, which as we all know isn’t always complete or up to date. Having the keyword there shows, right in the interface, that the author has committed to making this property compliant and keeping it that way in future releases.

The observable keyword could also allow one to set the KVO key string to something other than just the name of the property:

class MyObject {
	observable(somethingElse) var something: Int
}

You’d also need an annotation to tell the system which other key paths the property is dependent upon, which I’d probably do something like this:

class MyObject {
	observable var foo: Int
	observable var bar: Int {
		get { return self.foo }
		set(bar) { self.foo = bar }
		depends { return [“foo”] }
	}
}

The compiler could automatically add a CollectionType property to the class corresponding to each property, and then rewrite the property setter something like this (pseudocode):

class MyObject {
	private var observersOfFoo: [ObserverProtocol]?

	observable var foo: Int {
		set(newValue) {
			let oldValue = _foo

			_foo = newValue // or whatever the default setter usually does

			self.observersOfFoo?.forEach { $0.notifyKeyValueChanged(self, key: “foo”, oldValue: oldValue) }
		}
	}
}

I made it optional so that for the common case where there aren’t actually any observers on the property, the only performance costs are the store of the old value and checking an optional. Since optionals are basically enums, which are represented as an 8-bit integer which in this case can have the values 0 or 1, I’d expect checking an optional to have similar performance characteristics to checking a boolean, and thus I’d expect it to perform better than checking whether an array is empty, and doing some quick tests seems to back that up.

Charles

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


More information about the swift-evolution mailing list