+1

[ Long, sorry… ]

This version is a big step forward! Thanks for the continued work and 
comments...

I want to propose a small reframing that I think would help to clarify some of 
the remaining issues. It’s not really a “counterproposal” because I don’t think 
it actually changes all that much about the proposal. It’s more a question of 
how one conceptualizes the changes and fits them into the existing framework.

The gist is: let’s let the second shoe drop and admit that in the current 
proposal, “open” is now an access level modifier, pure and simple.

In the original proposal (and the ensuing discussion), there was tacit 
agreement that subclassability/overridability and access levels should be 
orthogonal. However, given the direction that the design has taken since then, 
I think we should revisit that decision.

open IS in fact an access level. I can’t say it any better than the proposal 
itself: “Since the first release of Swift, marking a class public has provided 
two capabilities: it allows other modules to instantiate and use the class, and 
it also allows other modules to define subclasses of it. Similarly, marking a 
class member (a method, property, or subscript) public has provided two 
capabilities: it allows other modules to use the member, and it also allows 
those modules to override it…This proposal suggests distinguishing these 
concepts. A public member will only be usable by other modules, but not 
overridable. An open member will be both usable and overridable. Similarly, a 
public class will only be usable by other modules, but not subclassable. An 
open class will be both usable and subclassable.”

In other words, subclassability/overridability always was an access level 
issue. All we are doing now is subdividing public into two separate sublevels, 
public and open. Just as public subsumes all the privileges of internal, open 
subsumes public.

Arguments:

First, the vast majority of resistance to this proposal (including my own, 
originally) has centered on the sense that coding options are being removed for 
potentially or partially ideological reasons (see SoftwareDevelopmentAttitude 
<http://martinfowler.com/bliki/SoftwareDevelopmentAttitude.html>), without 
clear value being offered in return. Reframing open as an access level 
completely nullifies this objection. “internal” is already the default access 
level, and the community seems very comfortable with this. For public APIs, 
developers are now simply required to make a neutral choice between public and 
open. There’s no strong-arming and no surprising imposition of new 
restrictions. Developers just have to make exactly the same, explicit access 
level decisions they did before. (For public API, the default is already so 
restrictive as to be moot. No accusations of “you picked the wrong default”!)

Second, framing open as an access level automatically resolves the ambiguity 
between proposal options #1 and #2, in favor of #1 (classes can be marked 
open). The reason there’s ambiguity about this choice is that there’s ambiguity 
about what open "really is.” Pin down exactly how open fits into the larger 
language, and the resolution is obvious. We already know what it means for a 
class and its members to have different access levels: the members are clamped 
to the access level of the container. All of the arguments that led to this 
convention — chiefly, that one may want to keep eventual publication in mind 
while developing and then be able to “flip the switch” in one place —  apply 
equally to the additional privileges of open.  

Third, developers already understand access levels and how they interact. If 
open is just an access level, all of this proposal’s changes can be fully and 
naturally described in one line: “public no longer includes the right to 
subclass or override. To get the behavior formerly known as public, use open 
instead.” Clear, concise, and not very controversial.

Fourth, bending over backwards to insist that open is not an access level leads 
to a variety of weird effects and special cases. For example, the fact that 
open implies public unless otherwise stated, which is mighty strange for 
modifiers that are supposedly orthogonal. Not to mention all the potential 
headbutts mentioned earlier by Xiaodi Wu; I agree that open in combination with 
internal seems oxymoronic. All of these nits would just go away if open were an 
access level. Again, all of this is the case because open really does quack 
like an access level and walk like an access level.

Points:

Q: “But what about access-leveled entities for which ‘open’ doesn’t make sense? 
What does ‘open struct’ mean?”
A: It doesn’t mean anything and should be an error. Simple. It’s not as if 
there weren’t all kinds of above-grammar-level restrictions in the current 
design…

Q: “What about conflicts with other modifiers, e.g. ‘open is not permitted on 
declarations that are explicitly final or dynamic’? Isn’t it weird that a 
simple access level could cause this kind of conflict?”
A: Au contraire, it’s final and dynamic that impose special requirements. You 
can just as easily flip this around: “final may not be applied to objects at 
the open access level”. Doesn’t that make more sense anyway?

Q: “You yourself (Garth) have argued that there’s no value to being able to 
forbid subclassing at the class level, and others have taken this position as 
well. So why are you now so eager to add ‘open’ to class definitions?”
A: Because it leads to a simple, consistent, and uncontroversial design. I do 
think there is value in being able to “flip the switch” at the class level as 
well. From the technical/compiler perspective, it seems like most benefits 
derive from method-level restrictions (as the current proposal seems to 
suggest). However, from the perspective of API clients, the top-level question 
is always going to be “should I be subclassing this or not?” I wouldn’t argue 
in favor of a class-level keyword just for the purpose of documenting 
intention, but since we get it for free with these other benefits, I’m all for 
it.

Garth


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to