[swift-evolution] [Idea] Extend "required" to methods other than init()
fulldecent at gmail.com
Mon Jan 18 10:08:10 CST 2016
This does not address the issue that a class may require all its
subclasses' initializers to call one of its initializers, but does not care
Are there other languages worth investigating which have the requires super
first/last semantics you note?
On Mon, Jan 18, 2016 at 10:19 AM, Matthew Johnson via swift-evolution <
swift-evolution at swift.org> wrote:
> > On Jan 17, 2016, at 5:54 PM, Jesse Squires via swift-evolution <
> swift-evolution at swift.org> wrote:
> > Hey all — this is my first reply to this list, so please forgive me if
> something goes wrong.
> > I wanted to elaborate more on Nate Birkholz's earlier message about
> extending the 'required' keyword to class methods, other than only init.
> > I had suggested this to Joe Groff on Twitter, and encouraged Nate to go
> ahead and start the thread. I’m just now finding the time to respond :) My
> goal here is to flesh out this idea a bit more, and hopefully get a more
> engaging discussion started.
> > Subclassing in Objective-C has the following deficiencies:
> > (1) It lacks the ability to formally declare if a method must be
> > (2) When overriding a method, there is no mechanism to enforce a call to
> super. You could use NS_REQUIRES_SUPER, but not only is this barely
> discoverable, it isn’t part of the language. Further, it merely generates a
> warning when library authors most likely intend for this to be an error.
> (Ok, one could treat warnings as errors, etc. etc.)
> > (3) It is easy for clients to override a superclass method without
> knowing it. That is, subclasses can simply implement an identical selector
> of the superclass without any kind of warning.
> > Clearly this is problematic. What happens when a subclass does not call
> super, but should? I think the only answer is "undefined behavior".
> Typically, the (not so great) solution here is documentation. This is
> common in Cocoa and CocoaTouch, for example each time you (never) read the
> docs, you'll see things like "your implementation must call super at some
> > Swift improves on these deficiencies in the following ways:
> > (1) For public methods (or internal for classes in the same module),
> Swift requires the 'override' keyword. This is great. Clients are now aware
> that they are overriding a superclass method. Though this *should* be an
> indication to the client that super might need to be called and the docs
> should be read (lol), clients are not required to do either.
> > (2) Superclasses can prevent overriding using the 'final' keyword. This
> provides a lot of safety but results in an "all or nothing" decision for
> library authors.
> > (3) For initializers only, Swift enforces the 'override' keyword *and* a
> call to super due to Swift’s strict initialization rules. Thus, client
> subclasses can safely override initializers. Woo!
> > (4) Additionally, for initializers only, Swift superclasses can require
> that subclasses implement a specific initializer using the 'required'
> keyword (given that a subclass provides a custom init). Again, augmenting
> the subclass initialization flow can be done safely. ::applause::
> > OK. Hopefully I didn’t miss anything there. As you can see, there’s one
> major deficiency remaining in Swift:
> > - If a subclass chooses to override a non-final method of its
> superclass, there is no mechanism to require a call to super.
> > My proposed solution is straight-forward: extend the use of 'required'
> to methods, rather than only allow this for init.
> > Behavior would be the following:
> > - A superclass can specify a method as 'required'.
> > - *If* a client’s subclass chooses to override a 'required' method, it
> must call super.
> > - Without the 'required' keyword, current behavior would remain the same.
> Thanks for bringing up this topic. I agree that we need to support more
> expressive semantics for overrides. I would take a slightly different
> approach though.
> Your use of `required` has a different semantic than its use for
> initializers. The change is arguably subtly, but it is meaningful. I
> don’t think it is a good idea for it to have different semantics in
> different contexts.
> For initializers `required` means “subclasses must provide an initializer
> with this signature. The fact that you have to call super just falls out
> of that because it is an initializer. You don’t actually have to call
> designated initializer that has the matching signature.
> You are suggesting making `required` mean “you must call the exact same
> method on super”. This would be unnecessarily limiting.
> There are 3 possible semantics for overridability:
> 1) final / not overridable
> 2) overridable
> 3) required
> I suggest expanding the use of `required` to mean #3 in general. I would
> also suggest changing the default to #1. That would require developers to
> think about subclasses before allowing overrides and also decide whether #2
> or #3 is the correct semantics when overriding is allowed (I know this is
> controversial and somewhat orthogonal to your idea). This would prompt the
> developer to think about the requirements to call super, which I discuss
> There are also 4 possible semantics for "super requirements” when you do
> 1) no call to super required
> 2) requires super (must call super *if overriden*)
> 3) requires super first
> 4) requires super last
> NS_REQUIRES_SUPER is equivalent to #2.
> The last two are somewhat subtle, but it is occasionally reasonable for a
> superclass to want its implementation to run before or after a subclass
> implementation. In both of these cases I would advocate for the compiler
> to automatically synthesize the call to super (if Swift supports these
> semantics) rather than requiring the developer to write the call. The
> annotation specifies the behavior and the manual call would be redundant.
> Swift doesn’t currently have any rules around calling super so we have #1
> as a de-facto default with no way to change that. That is probably ok as a
> default, especially if we require developers to think about subclasses when
> writing an overridable method (by making final the default). If we
> introduce syntax to specify 2-4 we would have all cases covered.
> Any of the “super requirements” could be specified in conjunction with
> either `overridable` or `required`. This allows more expressiveness than
> mixing the two concepts together would support.
> At minimum, I suggest that you use `required` as mentioned above and
> introduce new syntax to mean “must call the super implementation of the
> same method”. Adding “super first” and “super last” would be nice as well,
> but can also be added later if you’re not interested in those semantics.
> > Comments from Joe via twitter:
> > - "Should be straight forward to implement."
> > - "One interesting thing it would enable is invariant implementations of
> covariant protocol requirements." <dogScience.png>
> > Thanks for reading!
> > Jesse
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
> swift-evolution mailing list
> swift-evolution at swift.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution