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

Leonardo Pessoa me at lmpessoa.com
Mon Jul 18 16:42:03 CDT 2016


On 18 July 2016 at 16:06, Károly Lőrentey <swift-evolution at swift.org> wrote:
> On 2016-07-18 16:15:10 +0000, Leonardo Pessoa via swift-evolution said:
>
>> I believe sealed by default applied to functions makes the behaviour
>> consistent with classes and allows for the same behaviour we wanted
>> with this proposal. It would allows us to create subclassable classes
>> in which we would be able to internally override a method but not
>> outside the library and selectively allow other methods to be
>> overriden. Final won't do it so if this is not the default behaviour,
>> it will be necessary to introduce the sealed keyword so we can achieve
>> this.
>
>
> Can you give an example where you'd need such a sealed method, but the
> obvious pattern I described wouldn't work?

I'm not saying your pattern doesn't work; I'm saying it requires more code.

>> It's inconsistent to have to explicitly open a class and
>> explicitly seal its methods and vice-versa. It was my assumption that
>> when we chose sealed by default with the proposal we were talking
>> about everything and not just classes (I at least was talking
>> everything).
>
>
> This was my assumption as well, but then I thought things through. I suspect
> this might be what our friendly review manager was getting at when he gently
> lamented the lack of sufficient discussion on "overridable".
>
>> Introducing "dynamic" or some other keyword to mark explicitly methods
>> that should be overriden is just the same "open" with sealed methods
>> by default would mean for public methods so it makes no difference to
>> me.
>
>
> "dynamic" is already in the language. It changes method dispatch to use
> Objective-C style message passing, enabling advanced techniques based on the
> dynamic runtime, such as method swizzling or KVO. Since it already exists,
> I'm not arguing for its introduction; I merely want it integrated into the
> proposal, in order to keep the language coherent.

When I was talking "dynamic" here, I was meaning as in .NET (dynamic
is required to say a method can be overriden). Perhaps I was misguided
here.

>> Also having no default will not change that some library
>> developers will have everything sealed and selectively open.
>> No default shall also make developers prone to open to think more about
>> the keyword they'll choose to use,
>
>
> Exactly! For this particular corner of the language, it fulfills the
> "unwavering goal of requiring additional thought when publishing a class as
> public API". Forcing people to make an explicit choice is by far the most
> straightforward way to achieve this. It also has the nice property of being
> harder to interpret as a value judgement on overridability, which is clearly
> a topic that gets people's monocles popping. ಠ_ರೃ
>
>> but I'm not fond of no default.
>
>
> If adding an extra qualifier turns out to be an onerous requirement, we can
> choose a default at any time later, without breaking existing code. It'll
> probably be easier to do so once we have a little experience in actually
> using the new language.

So should we drop internal by default too?

>> As for the inheritance of openness, I firmly believe it shouldn't. If
>> a class inherited from an open class is open by default, there will be
>> no libraries making use of other libraries or we should also introduce
>> the sealed keyword in order to make the class (or method) sealed
>> again. This behaviour seems inconsistent to me too.
>
>
> Agreed.
>
>
>>
>> L
>>
>>
>> On 18 July 2016 at 09:07, Károly Lőrentey <swift-evolution at swift.org>
>> wrote:
>>>
>>> On 2016-07-18 09:17:43 +0000, David Hart via swift-evolution said:
>>>
>>>> On 18 Jul 2016, at 11:11, Xiaodi Wu via swift-evolution
>>>> <swift-evolution at swift.org> wrote:
>>>>
>>>> On Mon, Jul 18, 2016 at 3:27 AM, Brent Royal-Gordon via swift-evolution
>>>> <swift-evolution at swift.org> wrote:
>>>>>
>>>>> On Jul 17, 2016, at 8:57 PM, L. Mihalkovic via swift-evolution
>>>>> <swift-evolution at swift.org> wrote:
>>>>>
>>>>>> On Jul 17, 2016, at 9:14 PM, Garth Snyder via swift-evolution
>>>>>> <swift-evolution at swift.org> wrote:
>>>>>>
>>>>>> Is there a summary somewhere of the motivation for allowing methods to
>>>>>> be declared non-overridable within open classes?
>>>>
>>>> [...]
>>>> Garth: I think it's implicit in the reasons to prevent subclassing. The
>>>> mere fact that a class allows subclassing doesn't necessarily mean that
>>>> every member in it is designed to be subclassed. Consider
>>>> `UIViewController`: It's obviously designed to be subclassed, and some
>>>> methods in it (such as `loadView`) are intended to be overridden, but
>>>> others
>>>> (such as `loadViewIfNeeded`) are *not* intended to be overridden.
>>>>
>>>> And [if UIViewController were to be written in Swift] there'd be a good
>>>> reason why `loadViewIfNeeded` and others of its ilk couldn't be final?
>>>>
>>>> I don't know UIKit internals, but I could imagine loadViewIfNeeded be
>>>> overridden internally, if one knows the precise internal workings of
>>>> UIViewController. That would require open, to allow overriding
>>>> internally
>>>> but not externally.
>>>
>>>
>>>
>>>
>>> I thought about this aspect a little more. I think it's fair to say that
>>> we're breaking new ground for language design here. Classes limiting
>>> inheritance to a certain set of subclasses are nothing new (I've written
>>> &
>>> used classes doing this in C++, Java and C#), but no language that I know
>>> of
>>> allows limiting overrides of a specific public member in such a way. I
>>> think
>>> we need a convincing rationale for making this esoteric middle ground
>>> between final and open members the new default.
>>>
>>> The UIKit example above isn't convincing at all. It is already quite easy
>>> to
>>> allow package-internal subclasses to configure the behavior of
>>> loadViewIfNeeded without such a novel language feature. E.g., the UIKit
>>> team
>>> can simply make loadViewIfNeeded call into a non-final but internal
>>> method:
>>>
>>> public open class UIViewController {
>>> private var _view: UIView? = nil
>>>
>>> public final func loadViewIfNeeded() {
>>> internalLoadViewIfNeeded()
>>> }
>>>
>>> internal func internalLoadViewIfNeeded() { // overridable internally
>>> if let view = _view { return }
>>> loadView()
>>> }
>>>
>>> public open func loadView() {
>>> // Load it from a nib or whatevs
>>> }
>>> }
>>>
>>> I see no drawback to this pattern; it is quite clear and simple.
>>> Therefore,
>>> in the interest of keeping the language free of needless complexity, I
>>> suggest we change the proposal to remove the implicit "sealed" level of
>>> public member overridability, and support only "open" or "final" class
>>> members.
>>>
>>> For members, "open" should mean the opposite of "final", with no levels
>>> in
>>> between. Member-level openness should be entirely independent of
>>> visibility;
>>> so it should be possible to say "internal open" to mean an internally
>>> overridable member that's not at all visible outside the module -- the
>>> same
>>> as today's default.
>>>
>>> (Note that (on platforms with an Objective-C runtime) "dynamic" provides
>>> a
>>> third level of flexibility for class members; I argue that it should
>>> imply
>>> "open". So in order of increasing flexibility, we'd have "final", "open"
>>> and
>>> "dynamic" members. This seems easy enough to describe and understand.)
>>>
>>> I also suggest that for now, we should make neither "final" nor "open"
>>> nor
>>> "dynamic" the default for public members of open classes: we should
>>> rather
>>> require class authors to explicity add one of these qualifiers to all
>>> public
>>> member declarations. This way, we can defer the argument for choosing a
>>> default to a later (additive) proposal, once we have some experience with
>>> this setup. Non-public members can safely keep defaulting to "internal
>>> open", like they do today.
>>>
>>> --
>>> Károly
>>> @lorentey
>>>
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> --
> Károly
> @lorentey
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list