[swift-evolution] [Pitch] Changing NSObject dispatch behavior

Kevin Ballard kevin at sb.org
Mon Dec 19 13:57:20 CST 2016

On Fri, Dec 16, 2016, at 06:30 AM, Charles Srstka wrote:
>> On Dec 16, 2016, at 12:36 AM, Kevin Ballard <kevin at sb.org> wrote:

>> On Thu, Dec 15, 2016, at 03:01 PM, Charles Srstka wrote:
>>>> On Dec 15, 2016, at 4:33 PM, Kevin Ballard <kevin at sb.org> wrote:

>>>> The problem with that code isn't that `dynamic` doesn't work for
>>>> computed properties. It does; if you mutate the `foo` property,
>>>> you'll get the KVO notifications. The problem is you have one
>>>> property that depends on another and you didn't set up the KVO
>>>> machinery properly using automaticallyNotifiesObservers(forKey:) or
>>>> automaticallyNotifiesObserversOf<key>() (incidentally in Swift you
>>>> can write the latter as a `static let`, since that becomes a class
>>>> method in Obj-C).

>>> You’ll only get the notifications if you mutate ‘foo’ directly.
>>> This, however, is fairly useless, because if you are watching ‘foo’,
>>> you want to be notified every time the value changes, not just when
>>> someone hits one particular accessor. Code relying on observation of
>>> ‘foo’ in the example I provided would be prone to breaking in
>>> mysterious and possibly horrible ways.

>> No, if you implement keyPathsForValuesAffecting<key>()  then you get
>> "foo" KVO notifications when "bar" is mutated.  That's the whole
>> point of that method, and this is exactly what you have to do in Obj-
>> C as well.

> Right… the sentence I was quoting was talking about code which uses
> ‘dynamic’ but *doesn’t* use keyPathsForValuesAffecting<key>. You’ll
> get notifications if someone calls that one particular accessor, but
> otherwise you won’t.

You can always write buggy code. If you're using `dynamic` for KVO
purposes, then not implementing keyPathsForValuesAffecting<Key> in this
case is strictly a bug. If you're using `dynamic` for something other
than KVO, and your property won't end up supporting KVO properly by
default, then you should document it as such, given that the natural
assumption for a `dynamic` property is that it supports KVO.

>>>> So yes, `dynamic` by itself doesn't mean that the property supports
>>>> KVO. But there are very few reasons to use `dynamic` outside of
>>>> supporting KVO, so it's a pretty good signal that the property does
>>>> support it. And conversely, not having `dynamic` doesn't mean that
>>>> it doesn't support KVO, though if it does have manual KVO support
>>>> using will/didChangeValue(forKey:) then it should be documented as
>>>> such.
>>> Use of the ‘dynamic’ keyword enables all manner of runtime hackery
>>> which someone may be employing. The trick to automatically add KVO
>>> conformance to accessors is probably the most common, but it’s
>>> hardly the only one. One also might want to declare things ‘dynamic’
>>> when working with Objective-C frameworks not under one’s control
>>> which might assume the ability to do metaprogramming on your classes

>> That is exceedingly rare. I can't even remember the last time I used
>> such a thing.

> You used such a thing the last time you used KVO. ;-)

We were talking about metaprogramming other than KVO.

>>> I know it’s commonplace to use ‘dynamic’ all over the place wherever
>>> Core Data is involved.

>> It is? Why? Maybe you're confusing this with Obj-C's @dynamic
>> keyword, which is completely unrelated to Swift's `dynamic`. When
>> writing Swift NSManagedObject subclasses, you use the @NSManaged
>> property attribute, not the `dynamic` keyword (@NSManaged does
>> effectively the same thing that Obj-C's @dynamic, except it's
>> reserved for integration with CoreData instead of being as generic as
>> Obj-C's @dynamic is).

> @NSManaged implies dynamic, though. Core Data is entirely built on the
> dynamic runtime, and is using it pretty much everywhere.

@NSManaged could easily be implemented by codegenning static-dispatch
methods that invoke the primitive accessors and will/didChange KVO
broadcasts. Presumably it doesn't (presumably it does literally the same
thing @dynamic does in Obj-C, which is that it makes the assumption that
the methods exist at runtime even though they're unknown at compile-
time), but there's nothing about @NSManaged that requires it to always
use dynamic dispatch. Core Data leverages the dynamic runtime for method
generation, but it doesn't actually require it (you can completely
ignore dynamicism and implement your properties in terms of
primitiveValue(forKey:) and setPrimitiveValue(_:forKey:), though the dynamically-
synthesized primitive accessors are supposed to be more efficient).

>>> Long story short, ‘dynamic’ does not guarantee KVO conformance in
>>> any way, shape, or form.

>> And declaring that your property returns a String doesn't guarantee
>> that it actually does either. You can always write broken code. But
>> `dynamic` is required for automatic KVO conformance, and it's
>> extremely rare to have a reason to use `dynamic` outside of KVO, so
>> it's a really really strong signal that the property supports KVO. If
>> you're using `dynamic` on a property but don't support KVO correctly,
>> as you showed in your code example, that's a bug with your code.

> Correlation does not imply causation. Dynamic properties often support
> KVO, but the developer may have just declared it dynamic in order to
> use Objective-C’s dynamism to solve some other problem. You don’t
> know, and thus I certainly wouldn’t call it a bug in the code.

If a particular language feature is used 99.9% of the time to provide
some particular functionality, then people will assume the presence of
that language feature implies that functionality. I don't think it's
incorrect to assume that the overwhelming majority of uses of `dynamic`
are for KVO conformance.

-Kevin Ballard

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

More information about the swift-evolution mailing list