[swift-evolution] [swift-evolution-announce] [Review #2] SE-0117: Default classes to be non-subclassable publicly

Károly Lőrentey karoly at lorentey.hu
Tue Jul 19 12:34:52 CDT 2016


On 2016-07-19 11:35:03 +0000, Brent Royal-Gordon via swift-evolution said:

>> 
>> On Jul 19, 2016, at 4:00 AM, Károly Lőrentey via swift-evolution 
>> <swift-evolution at swift.org> wrote:
>> 
>> "dynamic final" is prohibited by the current version of compiler.
> 
> Huh, I didn't know that. I don't agree with that design.
> 
> (However, I do notice that a `final` class can have `dynamic` members.)

I'm very very far from understanding how Swift interacts with the Obj-C 
runtime, but I believe that might be a bug. I do not expect e.g. KVO to 
work correctly on these. I don't think the Objective-C runtime 
understands or enforces final (at neither class nor member level), and 
I expect abusing it to break out of "final" (at either level) could 
violate critical compile-time assumptions and cause deep problems. I 
think this also applies to anything with @objc that isn't also declared 
dynamic -- even "@objc open" members aren't necessarily dispatched via 
message passing, are they?

>> Can you provide an example of a problem that would be solved by allowing it?
> 
> In our current Objective-C world, the obvious example would be an 
> NSObject subclass with a property that should not be overridden (so you 
> want to mark it `final`), but which participates in KVO (so in fact 
> Foundation will use the Objective-C runtime to invisibly subclass the 
> class, override the setter, and change the type of the instance to the 
> subclass). I believe it makes perfect sense to declare such a property 
> `dynamic final`; the Objective-C-level overriding performed by 
> Foundation is an implementation detail, and does not change the fact 
> that you should never declare an override of that property.

To me, it doesn't make much sense to declare that a property must not 
be overridden, then expect KVO to be able to override it anyway. 
"dynamic" clearly does allow overriding (and more); it just adds 
supports for a less convenient syntax. AFAIK KVO isn't using secret 
APIs that aren't also available to my API clients. If I choose to use 
"dynamic" in my API, then I have to design for whatever the Objective-C 
runtime supports, and that includes overrides. Only disallowing 
overrides with Swift syntax doesn't seem to be much of a win here.

I'm not saying we couldn't come up with some coherent definition for a 
hypothetical "final dynamic"; I just really don't see what would be the 
point of it, besides making the language more complicated.

> It's not really clear how `dynamic` would be used without Objective-C, 
> but I could imagine analogous situations, like an ORM implementing Core 
> Data-style faults using dirty, low-level class-changing hacks. A class 
> that was *semantically* `final`, and thus ought to be eligible for 
> static dispatch, might thus require dynamic dispatch anyway.

It is nice (and critically important) that we can keep using Cocoa in 
Swift; but supposing we wanted to create a brand new ORM for a 
hypothetical "Swifty Cocoa", it wouldn't make much sense to do it using 
the same runtime techniques as Core Data. (After all, we already have 
such a framework in Swift; it's called Core Data.) I'd prefer to choose 
a swiftier approach, like generating the equivalent of 
NSManagedObject's model-specific boilerplate at compile time.

<off-topic>
Cocoa currently hides the boilerplate for all of these wonderful 
constructs behind amazingly effective runtime acrobatics. This fits 
perfectly into Objective-C, and it also works very well in Swift. But 
such features could be in better harmony with Swift's unique set of 
language constructs if their boilerplate was hidden behind amazingly 
effective **compile-time** acrobatics instead.

Such compile-time acrobatics are hard to perform today, and it is 
possible that the ability to create such systems will forever remain an 
advanced skill, just like forging runtime magic requires advanced 
skills in Objective-C.

But Swift doesn't have an analogue to objc/runtime.h yet. What will 
such a thing look like? A general metaprogramming/DSL subsystem (like 
some form of hygienic macro engine)? A family of narrowly scoped 
language/compiler features that provide extensible syntactic sugar to 
get rid of specific kinds of boilerplate (like property behaviors or 
coroutines)? A set of standalone tools for generating Swift source code 
(like mogenerator)? Something else? Some combination of these?

I'd like to move on from the Objective-C runtime and start exploring 
this rich new frontier; I think it's awesome that Swift isn't *just* a 
bracket-free dialect of Objective-C.

I'm sorry for derailing the discussion. I think we agree on most of 
this, anyway.
</off-topic>

-- 
Károly
@lorentey




More information about the swift-evolution mailing list