[swift-evolution] Closure identity (was Re: Compiler directive for current closure reference)

Brent Royal-Gordon brent at architechies.com
Tue Feb 23 17:09:35 CST 2016

> Even without these optimization considerations, relying on the identity of specific block objects is fraught with problems, and in practice there's usually a better discriminator available to you somewhere to key on.

I'm sorry, but I'm really having trouble understanding this point of view. Consider this:

	behavior var observable<Value where Self: class>: Value {
		typealias Observer = (observed: Self, oldValue: Value, newValue: Value) -> Void

		private var value: Value = initialValue
		// This would be better as a Set by making functions Hashable, but I understand
		// that compound types currently can't be conformed to protocols.
		private var observers: [ObjectIdentifier: Observer]
		func addObserver(observer: Observer) {
			observers[ObjectIdentifier(observer)] = observer
		func removeObserver(observer: Observer) {
			observers[ObjectIdentifier(observer)] = nil
		get { return value }
		set {
			let oldValue = value
			value = newValue
			for observer in observers.values {
				observer(observed: self, oldValue: oldValue, newValue: newValue)

What is the better discriminator here? Sure, you could make Observer into a class that contains a closure, but how does that make anything better? It's an extra object to track and manage; it's an impediment to using trailing closure syntax with `addObserver`; it's more state you could accidentally share; it's additional memory and additional reference counting.

If there are implementation reasons not to support it, fine. But let's not pretend we're doing people a service by preventing this, like when we prevent enum extensions from adding cases to make code correctness more decidable, or that we're reflecting some fundamental semantic truth, like when we don't give value types identities because they get implicitly copied around and independently mutated.

There are perfectly sensible ways to define closure identity—a particular (source-level) function with a particular context, or a closure captured at a particular point in the program's execution—but we don't support the operation because we'd have to either spend extra memory on something rarely used, or give up very useful optimizations. There's no shame in that, and no need to try to turn it into a positive instead of something negative but necessary.

Brent Royal-Gordon

More information about the swift-evolution mailing list