Kevin, I feel like our messages came in the opposite order — my previous message is essentially an answer to what you wrote!
I agree that Apple is going to think carefully about what is subclassable / overridable when given that option. I agree that third-party library authors ought to do this as well. I disagree that either party will always get it right. Of course they won’t. My musings below are about what happens in this inevitable situation when library authors inevitably, in a well-advised abundance of caution, leave things too limited. I generally support this proposal, and the broader principles it embodies. I just want to sound a note of caution about its impact, and its repercussions for library authors (especially but not only Apple). Let’s not neglect the “half-sized oatmeal” problem, or naively assume that wisdom alone can prevent it. Cheers, Paul > On Dec 22, 2015, at 1:31 PM, Kevin Ballard via swift-evolution > <[email protected]> wrote: > > UIKit classes aren't subclassable because of a lack of sealed-by-default, > they're subclassable because until very recently there was no way to mark > classes as not being subclassable. Many classes in UIKit are designed to > handle subclassing, but some classes are not designed to handle that, and are > explicitly documented as saying that you shouldn't subclass them because they > won't work right. Assuming a future in which UIKit is reimplemented in Swift, > every class today that is not explicitly documented as saying "don't subclass > this" would presumably be marked as inheritable. And the classes that say > "don't subclass this" may very well be final/sealed, and that's perfectly OK > because subclassing them doesn't work properly anyway. > > Whether the language has final-by-default/sealed-by-default doesn't really > affect this in any way. I guarantee you that once Apple starts putting Swift > code in their frameworks, every single framework class Apple releases is > going to make an explicit decision about being final/sealed vs inheritable, > and the language defaults won't affect that one bit. > > The only thing that final-by-default/sealed-by-default is going to affect is > third-party code that is released without carefully thinking about this > issue. And really, any code that is released that doesn't explicitly think > about this issue is likely to have issues with subclassing anyway (because > the developer didn't give any thought to whether subclasses would be allowed > and likely made assumptions in various places that it wouldn't, even if they > didn't consciously think about it). That said, I do think it's a really good > idea for anyone releasing libraries to make an explicit decision about > whether the class should be final/sealed or inheritable. > > One benefit I haven't seen mentioned about this proposal is it makes it > obvious when the author has made an explicit decision. Today there's no > keyword for inheritable, so if a class doesn't say `final` you can't know if > that was explicit or implicit. But with this proposal, we'll have to gain an > `inheritable` keyword (and presumably a `sealed` keyword if we get sealed > behavior), which means every single class can be annotated with a keyword > indicating an explicit decision was made. Sure, people could still leave off > the keyword when they explicitly choose the default behavior, but we could > encourage a habit of always adding the keyword even if it's for the default > behavior just to indicate that this decision was intentional. > > -Kevin Ballard > > On Tue, Dec 22, 2015, at 09:03 AM, Paul Cantrell via swift-evolution wrote: >> Joe’s and Brent’s writeups copied below really get to the heart of this for >> me. This is a tough question, and I find myself torn. I’m sympathetic to >> both lines of argument. >> >> It’s not entirely true that “you can never take back” overridability — you >> can make a breaking API change with a new major version, of course — but >> it’s a compelling point nonetheless. One default is clearly safer than the >> other, at least for the library author. “Safe by default” is indeed the >> Swift MO. (Well, except for array subscripting. And any public API involving >> tuples, for which any change, even type widening, is a breaking change. >> And….OK, it’s not absolute, but “safe by default” is the MO 95% of the >> time.) “Final by default” just seems more Swift-like to me. >> >> Despite that, Joe, I have to agree with Brent on his central point: the >> perspective that comes from spending a lot of time _writing_ libraries is >> very different from one who spend more time _using_ them. Yes, UIKit is not >> going to be rewritten in Swift anytime soon, but Brent is rightly imagining >> a future where the Swift way is The Way. >> >> I weigh the safety argument against the many long hours I’ve spent beating >> my head against library behaviors, wishing I could read UIKit’s source code, >> wishing I could tweak that one little thing that I can’t control, and being >> grateful for the dubious workaround that saves the day — yes, even when a >> subsequent OS update breaks it. I know what I’m getting into when I solve a >> problem with a hack, and if the hack ships, it’s only because I weighed the >> risks and benefits. We app developers rely on swizzling, dubious >> subclassing, and (especially) undocumented behavior far more often than any >> of us would like. It is just part of the reality of making things ship — and >> an important part of the success of Apple’s app ecosystem. >> >> This debate reminds me of something that often happens when a >> humans-and-paper process moves to software. When the software starts >> rigorously enforcing all the rules the humans were theoretically following >> all along, and it turns out that quite a lot of in-the-moment nuanced human >> judgement was crucial to making everything work. With nuance removed, things >> fall apart — and instead of things at last achieving the rigor that seemed >> so desirable in theory, the process has to explicitly loosen. (At the local >> coffee shop, a new iPad-based POS system suddenly made it an “uh let me get >> the manager” moment when I want to get the off-menu half-sized oatmeal I’ve >> always got for my toddler.) >> >> I’m not totally opposed to final by default. Joe’s arguments sway me in >> principle. In practice, if Swift does indeed moves us toward “less wiggle >> room, less hackable” by default, then that wiggle room _will_ have to come >> from somewhere else: perhaps more open sourcing and more forking, or faster >> turnaround on fixes from library authors, or a larger portion of time spent >> by library authors explicitly exposing and documenting customization points. >> The new effort involved for library authors is nothing to sneeze at. >> >> Cheers, >> >> Paul >> >> >>> On Dec 22, 2015, at 9:46 AM, Joe Groff via swift-evolution >>> <[email protected]> wrote: >>> >>> I think a lot of people in this thread are conflating "final by default" or >>> "sealed by default" with "sealed everywhere". No matter what the default >>> is, the frameworks aren't going to suddenly rewrite themselves in Swift >>> with final everything; Objective-C will still be what it is. Furthermore, >>> we're only talking about language defaults; we're not taking away the >>> ability for frameworks to make their classes publicly subclassable or >>> dynamically overrideable. That's a policy decision for framework authors to >>> make. The goal of "sealed by default" is to make sure the language doesn't >>> make promises on the developer's behalf that they weren't ready to keep. >>> ObjC's flexibility is valuable, and Apple definitely takes advantage of it >>> internally all over place; Apple also has an army of compatibility >>> engineers to make sure framework changes work well with existing software. >>> Not every developer can afford that maintenance burden/flexibility >>> tradeoff, though, so that flexibility is something you ought to opt in to. >>> You can always safely add public subclassability and dynamic >>> overrideability in new framework versions, but you can never take them back. >> >> >>> On Dec 22, 2015, at 12:31 AM, Brent Royal-Gordon via swift-evolution >>> <[email protected]> wrote: >>> >>> Just imagine going through UIKit and marking every class inheritable *by >>> hand*—no cheating with a script—and you'll have some idea of the additional >>> burden you'll be imposing on developers as they write their code. The >>> proposals that every single method should be explicitly marked as >>> overridable are even worse; frankly, I don't think I'd want to use Swift if >>> you forced me to put a `virtual` keyword on every declaration. >>> >>> I worry that the team's use of Swift to build the standard library, and >>> their close association with teams building OS frameworks, is biasing the >>> language a little bit. I think that, in all likelihood, most Swift code is >>> in individual applications, and most libraries are not published outside of >>> a single team. If I'm right, then most Swift code will probably be quite >>> tolerant of small but technically "breaking" ABI changes, such as making a >>> class `final`, or (as mentioned in another thread) making a closure >>> `@noescape`. >>> >>> That won't be true of published library code, of course. But published >>> library code is a small minority of the Swift code people will write, and >>> it already will require greater scrutiny and more careful design. >>> >>> There is already a good opportunity to reflect on whether or not an API >>> should be `final`. It's when you put the `public` keyword on it. I think >>> programmers will have a better, easier time writing their code if, in this >>> case, we put a little bit of trust in them, rather than erecting yet >>> another hoop they must jump through. >>> >>> Perhaps we could even provide a "strict interfaces" mode that published >>> frameworks can turn on, which would require you to declare the heritability >>> of every class and member. But even that may not be a good idea, because I >>> also suspect that, in the field, most published libraries probably have to >>> be extended in ways the library's author did not expect or anticipate. >>> >>> This means doing some dangerous overriding, yes. But a UI that breaks after >>> an iOS upgrade is not nearly as dangerous to my business as a three-month >>> delay while I reimplement half of UIKit because someone in Cupertino >>> thought they knew what I need better than I do and turned off—or even >>> worse, *left turned off without a single thought*—subclassing of >>> UIBarButtonItem. >>> >>> The bottom line is this: Your users like Swift's strictures when they're >>> helpful. *This stricture is not helpful.* Library users don't accidentally >>> subclass things, and with the `override` keyword in Swift, they don't >>> accidentally override them either. And where it truly is important, for >>> safety or for speed, to prevent subclassing, we already have `final`. >>> Making it the default is less safety than suffering. >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
