[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