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

Károly Lőrentey karoly at lorentey.hu
Mon Jul 18 07:07:54 CDT 2016


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




More information about the swift-evolution mailing list