<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">[Proposal: <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md</a> ]<div class=""><br class=""></div><div class="">John has done a tremendous job supporting this proposal; the position he’s articulated very closely matches mine. Thank you to both John and Javier. </div><div class=""><br class=""></div><div class="">I wanted to share a concrete use case that Daniel Dunbar relayed to me. He was working on a closed class hierarchy like the ones discussed here, where all of the subclasses are within a single module, but they are all public. The class <i class="">also</i> has a required initializer for dynamic construction, so that they could write something like this:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">internal struct ModelContext { /*…*/ }</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class=""></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">public class ModelBase {</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""> internal required init(context: ModelContext) { /*…*/ }</blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""> // …</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">}</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">public class SimpleModel: ModelBase {</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""> internal required init(context: ModelContext) { /*…*/ }</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">}</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">public class MoreComplicatedModel: ModelBase { /*…*/ }</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class=""></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">// (within some other type)</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">public func instantiateModelObject<Model: ModelBase>(_ type: Model) -> Model {</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""> return type.init(context: self.context)</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">}</blockquote><div class=""><br class=""></div>That is, a <i class="">public</i> entry point calls a required initializer with an <i class="">internal</i> argument type. This is the only way to instantiate Model objects, and the internal context type doesn’t leak out into the public API.<div class=""><br class=""></div><div class="">Of course, Swift doesn’t allow this. If someone outside of the module subclasses ModelBase, there’s no way for them to provide the dynamically-dispatched 'init(context:)’, because they don’t have access to the internal ModelContext. The author of the library has to make the required initializers public, and either set the ModelContext separately or make it public as well. Even though no one outside the module should be using these APIs.</div><div class=""><br class=""></div><div class="">If ModelBase were public-but-not-subclassable, however, the code is perfectly fine. The initializer and the helper type don’t need to be public, and clients of the library see only what they need.<br class=""><div class=""><br class=""></div><div class="">This is just one use case. I don’t want to say it’s a general model for everyone’s code. However, it does point to a <i class="">desire</i> for public-and-not-subclassable classes; any other solution would either require the library author making more things public, or the compiler making it possible to accidentally call an unimplemented initializer.</div><div class=""><br class=""></div><div class="">I’ll send a separate message with my thoughts as the primary author of the Library Evolution model, to keep those discussions distinct. That one will have a bit more ideology in it. :-)</div><div class=""><br class=""></div><div class="">Jordan</div></div><div class=""><br class=""></div><div class="">P.S. “Why not use protocols?” When a protocol has an initializer requirement, it still forces all subclasses of a conforming class to provide an implementation, i.e. the conforming class’s initializer still needs to be declared ‘required’. That means it’s subject to the same restriction: a required initializer must have as much access as the containing class.</div></body></html>