[swift-evolution] Proposal: Add @requires_super attribute

Marc Knaup marc at knaup.koeln
Wed Dec 16 13:36:39 CST 2015


PS: Just swap "init()" for "func foo()" and you have the syntax for
functions which require super calls in subclasses :)


On Wed, Dec 16, 2015 at 8:34 PM, Marc Knaup <marc at knaup.koeln> wrote:

> I assume you just forgot "func".
>
> Okay, in the case where the super implementation is not "required" but the
> subclass starts using "required" you must specify both.
>
> This is the same as the current behavior for initializers:
>
> class A {
> init() {}
> }
>
> class B: A {
> required override init() {}
> }
>
> class C: B {
> required init() {}
> }
>
>
> Btw I just noticed that my previous assumption was wrong. Subclasses can
> always use "override" and "required". For class "C" it would just yield a
> warning because it's redundant.
>
> On Wed, Dec 16, 2015 at 8:29 PM, Ian Ynda-Hummel <ianynda at gmail.com>
> wrote:
>
>> Well, consider the following:
>>
>>     class Foo {
>>         func foo() {
>>
>>         }
>>     }
>>
>>     class Bar: Foo {
>>         override required foo() {
>>
>>         }
>>     }
>>
>>     class Baz: Bar {
>>         override(?) required foo() {
>>
>>         }
>>     }
>>
>> The override would be required for Bar. If not it's either making
>> assumptions about the superclass that may not be correct or no subclass can
>> make an overridden method required by its subsequent subclasses.
>> Initializers have the convenience of always being required for the root
>> class.
>>
>> Now I think I'm talking myself out of the initializer behavior being
>> correct. I'll just call myself undecided about that for now.
>>
>>
>> On Wed, Dec 16, 2015 at 2:22 PM Marc Knaup <marc at knaup.koeln> wrote:
>>
>>> When requiring super's implementation to always be called Swift should
>>> not make the assumption that two methods with the same name but different
>>> signatures are interchangeable.
>>> Only the super method with exactly the same signature - i.e. the
>>> overridden one - should be allowed to called. Anything else will likely be
>>> complex and confusing.
>>>
>>> @Ian "override" keyword is neither necessary nor allowed when "required"
>>> is used since it implies exactly that already.
>>>
>>> On Wed, Dec 16, 2015 at 8:17 PM, Ian Ynda-Hummel via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>> @Jordan I might slowly be convincing myself that initialization
>>>> behavior is correct, though. For example, this feels right:
>>>>
>>>>     class Foo {
>>>>         required func foo() {
>>>>
>>>>         }
>>>>     }
>>>>
>>>>     class Bar: Foo {
>>>>         required func foo(bar: Bar) {
>>>>             super.foo()
>>>>         }
>>>>     }
>>>>
>>>> This, however, feels less right:
>>>>
>>>>     class Foo {
>>>>         required func foo(string: String) {
>>>>
>>>>         }
>>>>
>>>>         required func foo(url: NSURL) {
>>>>
>>>>         }
>>>>     }
>>>>
>>>>     class Bar: Foo {
>>>>         override required func foo(string: String) {
>>>>             super.foo(url: NSURL(string: string)!)
>>>>         }
>>>>     }
>>>>
>>>> But regardless, I'm having trouble coming up with a better keyword.
>>>>
>>>> fo
>>>> On Wed, Dec 16, 2015 at 2:03 PM T.J. Usiyan <griotspeak at gmail.com>
>>>> wrote:
>>>>
>>>>> +1
>>>>>
>>>>> I thought that there must have been some reason not to include it that
>>>>> I hadn't considered when it wasn't in Swift 1.0.
>>>>>
>>>>> On Wed, Dec 16, 2015 at 1:59 PM, Jordan Rose via swift-evolution <
>>>>> swift-evolution at swift.org> wrote:
>>>>>
>>>>>> My hesitation about "required" is that required initializers don't
>>>>>> have to call the *same* initializer, which is something that
>>>>>> NS_REQUIRES_SUPER *does* enforce. (In fact, this new attribute could
>>>>>> very well apply to required initializers as well: if you implement this
>>>>>> initializer, you must chain to the same initializer. I'm not quite sure
>>>>>> when that would come up, but it's potentially useful.)
>>>>>>
>>>>>> Jordan
>>>>>>
>>>>>> On Dec 16, 2015, at 10:56 , Ian Ynda-Hummel via swift-evolution <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>>
>>>>>> +1 for this if for nothing else but UIKit classes yelling at me to
>>>>>> call super.viewDidLoad().
>>>>>>
>>>>>> I think using the required keyword makes sense. The one possible
>>>>>> caveat is overloading, as my knee jerk reaction is that methods of the same
>>>>>> name would behave like initializers. So a method overriding a required
>>>>>> method would have to call a required method of the same name on the
>>>>>> superclass if one exists. I'm not convinced that's correct, though.
>>>>>>
>>>>>> On Wed, Dec 16, 2015 at 1:40 PM Marc Knaup via swift-evolution <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>>
>>>>>>> "required" also doesn't mean that a subclass has to implement the
>>>>>>> required initializer since it can be inherited.
>>>>>>> Your example is an abstract function which should have it's own
>>>>>>> keyword (if we ever get abstract functions).
>>>>>>>
>>>>>>> On Wed, Dec 16, 2015 at 7:37 PM, Vester Gottfried <
>>>>>>> vester.gottfried at gmail.com> wrote:
>>>>>>>
>>>>>>>> I think reusing required would send the wrong message. Required
>>>>>>>> would mean for me something like NSOperation subclasses maybe require to
>>>>>>>> have a main() function, but that doesn't mean you have to call super. On
>>>>>>>> the contrary, the documentation of NSOperation main() explicitly states not
>>>>>>>> to call super.
>>>>>>>>
>>>>>>>> On Wed, Dec 16, 2015 at 7:08 PM, Marc Knaup <marc at knaup.koeln>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> What about re-using the "required" keyword in the superclass which
>>>>>>>>> already means something similar for initializers?
>>>>>>>>> Subclass implementations are required to call super's
>>>>>>>>> implementation.
>>>>>>>>> If a subclass doesn't implemented the required method it could
>>>>>>>>> mean that it inherits the behavior from the superclass - just like
>>>>>>>>> initializers can be inherited too.
>>>>>>>>>
>>>>>>>>> On Wed, Dec 16, 2015 at 7:02 PM, Jordan Rose <
>>>>>>>>> jordan_rose at apple.com> wrote:
>>>>>>>>>
>>>>>>>>>> +1 from me. FWIW, the Objective-C one is syntactic.
>>>>>>>>>>
>>>>>>>>>> Information from Radar: the request for this is
>>>>>>>>>> rdar://problem/17408107 (plus a few duplicates). One of the dups
>>>>>>>>>> suggests a variation where a subclass method can be declared as "refine"
>>>>>>>>>> instead of "override" so that you can document that your *own* method
>>>>>>>>>> is expected to call super. In this model, "@requires_super" could become
>>>>>>>>>> something like "imposed". I personally think this doesn't add enough,
>>>>>>>>>> especially since we wouldn't be publishing refine-vs-override in a
>>>>>>>>>> library's public interface.
>>>>>>>>>>
>>>>>>>>>> Jordan
>>>>>>>>>>
>>>>>>>>>> On Dec 16, 2015, at 9:49 , Marc Knaup via swift-evolution <
>>>>>>>>>> swift-evolution at swift.org> wrote:
>>>>>>>>>>
>>>>>>>>>> Sounds reasonable since even the best flow analysis cannot ensure
>>>>>>>>>> that all codepaths call the super implementation.
>>>>>>>>>>
>>>>>>>>>> Some more edge cases:
>>>>>>>>>>
>>>>>>>>>>    - Calling super asynchronously by using it in a closure
>>>>>>>>>>    - Referring to the super implementation by assign it to a
>>>>>>>>>>    variable and call it later (is that really possible? never did that)
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Wed, Dec 16, 2015 at 6:25 PM, Vester Gottfried <
>>>>>>>>>> vester.gottfried at gmail.com> wrote:
>>>>>>>>>>
>>>>>>>>>>> I would suggest that @requires_super only checks if a call to
>>>>>>>>>>> super is present at all. More detailed behaviour should be part of the
>>>>>>>>>>> functions documentation, because I think all possibilities cannot be
>>>>>>>>>>> checked easily by the compiler. For example a call to super my be required
>>>>>>>>>>> to happen early or late inside the function. But when too early or too late
>>>>>>>>>>> is can probably not been forseen by the compiler.
>>>>>>>>>>>
>>>>>>>>>>> On Wed, Dec 16, 2015 at 5:46 PM, Marc Knaup <marc at knaup.koeln>
>>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> +1 always had such issues with UIViewController's lifecycle
>>>>>>>>>>>> methods.
>>>>>>>>>>>>
>>>>>>>>>>>> But edge cases need to be considered like "throws" for example.
>>>>>>>>>>>> Do I need to call super before I throw something?
>>>>>>>>>>>>
>>>>>>>>>>>> On Wed, Dec 16, 2015 at 5:41 PM, Matthew Johnson via
>>>>>>>>>>>> swift-evolution <swift-evolution at swift.org> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> +1 to this.  Anything that helps ensure inheritance is thought
>>>>>>>>>>>>> through carefully and used correctly is a win.
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Dec 16, 2015, at 10:32 AM, Vester Gottfried via
>>>>>>>>>>>>> swift-evolution <swift-evolution at swift.org> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Some class based libraries/frameworks expect the consumer to
>>>>>>>>>>>>> subclass certain classes and override specific method and require that the
>>>>>>>>>>>>> super implementation of an overridden method is being called.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Not calling the super implementation is a common source of
>>>>>>>>>>>>> bugs that may be prevented if the compiler checks if super is called, like
>>>>>>>>>>>>> it does in some cases of init().
>>>>>>>>>>>>>
>>>>>>>>>>>>> Example:
>>>>>>>>>>>>>
>>>>>>>>>>>>> class Box {
>>>>>>>>>>>>>    @requires_super
>>>>>>>>>>>>>     func addStuff() { ... }
>>>>>>>>>>>>> }
>>>>>>>>>>>>>
>>>>>>>>>>>>> Overriding class Box's addStuff without calling
>>>>>>>>>>>>> super.addStuff() should result in an error
>>>>>>>>>>>>>
>>>>>>>>>>>>> class Chest : Box {
>>>>>>>>>>>>>     override addStuff() {
>>>>>>>>>>>>>          // ERROR: addStuff() requires call to super.addStuff()
>>>>>>>>>>>>>         ...
>>>>>>>>>>>>>     }
>>>>>>>>>>>>> }
>>>>>>>>>>>>>
>>>>>>>>>>>>> Objective-C developers know this as NS_REQUIRES_SUPER and I
>>>>>>>>>>>>> think its worth thinking about adapting it.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I hope my proposal was clear and thanks for reading,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Gottfried
>>>>>>>>>>>>>  _______________________________________________
>>>>>>>>>>>>> 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
>>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>  _______________________________________________
>>>>>>>>>> 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
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>
>>>>>> _______________________________________________
>>>>>> 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
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>>>
>>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151216/6a5a3327/attachment.html>


More information about the swift-evolution mailing list