> On Jul 20, 2016, at 10:13 AM, Károly Lőrentey <[email protected]> wrote: >> On 2016-07-18, at 19:05, John McCall via swift-evolution >> <[email protected]> wrote: >> The basic effect of Károly's counter-proposal is that every public member of >> an open class has to be marked either "open" or "final". That's boilerplate. > > My primary point was that there is no need for a middle ground between > "final" and "open" members. > > I want to push my primary point a little more, so let’s forget my secondary > suggestion to have no default, and let’s set an implicit choice. > > I'd still argue for having no middle ground. “final” seems to be a good > default; its effect matches the proposal. > >> I think you and Károly are evaluating the addition of non-open methods as if >> they were being added primarily to increase expressive capabilities. They >> do marginally increase expressiveness, but I agree that it's not a common >> situation to explicitly want. However, neither are non-open classes. > > It's more of an Occam's razor thing. The proposal prevents people from > unintentionally exposing a wider API area than they intended. I agree with > this wholeheartedly. I just don't believe that we need to add a brand new > access level for members to achieve this goal. > > Having an implicit "sealed" class level is a much easier sell for me, because > it is sometimes desirable to expose a sealed class hierarchy, but Swift > doesn't currently support it well -- AFAICT not as an intentional choice, but > rather as an unfortunate side-effect of the initializer rules. You could've > simply chosen to propose making "final" the default for public classes. > Kotlin's troubles mostly wouldn't apply as long as internal classes would > remain open, so I'd have supported that too. But rather than this, the > proposal is built on top a nice solution to the sealed class problem. Solving > it is obviously a good idea, and it is closely related to the goal of the > proposal. > > There is no such language problem in Swift 2 with sealed methods: an internal > open member is sealed by virtue of not being externally visible. It’s > straightforward to add a public final trampoline in the rare case when a > sealed member should also be made externally callable. I believe the proposal > works perfectly well without adding a language feature for this uncommon > usecase. > >> The goal here is not to create new expressive power, it's to establish a >> comprehensible intermediate position that's acceptable as a default so that >> publicizing an API doesn't require so much annotation and bookkeeping. >> Otherwise, programmers are forced to immediately decide between >> over-promising (by making the method publicly overridable) or breaking their >> own code (if they have internal overrides). > > But making API public should never be done in a hurry. It includes making the > API presentable, which involves some amount of refactoring. Granted, if an > API has internally overridden methods that the author wants to make public > but sealed, then they'd need to refactor these methods. But given how rare > this is, and how easy it is to implement the trampoline pattern, is such a > trivial refactoring step really too much to ask? (There are a number of much > more complicated refactorings involved in making an API public; e.g., it is > often the case that a method I want to make public has a parameter or return > value with a type that I wish to keep internal.)
I agree that having the concept of "visible publicly but only arbitrary modifiable internally" adds complexity to the language. However, once we've got non-open public classes — and as I understand it, you still support those — that complexity already exists. You're not really eliminating anything by preventing this from being applied to methods. Also, we're going to be proposing a lot of new things for library-resilience over the next six months or so that will add appreciable but unavoidable complexity to the language around module boundaries. Module boundaries have a lot of special significance in the language design because Swift takes the stable binary interface problem much more seriously than, I think, almost any other language can claim to. > I believe that apart from this one little wrinkle, the behavior that SE-0117 > proposes can be fully implemented by allowing just "final", "open" and > "dynamic" members, with "final" being the default for public members of open > classes, and "open" being the default for all other members (including > non-open classes). > > Is smoothing out that wrinkle worth introducing a whole new default level of > member overridability? I think this is worth some more discussion. > > Note that if we end up with "final” members by default and it turns out to be > the wrong choice, changing the default to sealed would not be a > source-breaking change. > >> Furthermore, I don't agree that non-open methods add significant new >> complexity. For clients of a library, a non-open method is final; there are >> no semantically-detectable differences (ignoring covariant overrides). >> Within a library, non-open methods remove the need for some unnecessary >> bookkeeping. And just on a conceptual level, the analogy to class behavior >> is quite simple. > > This reminds me: Whether or not we allow the sealed level on methods, I > suggest we provide a contextual keyword to (optionally) spell it. A "sealed" > keyword is the obvious choice. This would encourage people to use common > terminology, and makes it easier to use search engines to find an explanation > of the concept. Autogenerated API summaries should add the "sealed" keyword. Yes, we should probably add some way to spell it. "sealed" does not feel like a natural opposite to "open", however, and I think we're quite taken with "open". I would suggest "nonopen" or "closed". John. > > We never have to spell "internal", but I think it is still very useful that > it exists. > > -- > Károly > @lorentey > _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
