<div dir="ltr">+1 to most of what Andrew Bennet said.<br><div><br></div><div>I also disagree that implicit calls is the right solution. If the compiler autocompletes the super call for me, there&#39;s little reason for this. It just makes debugging much harder.</div><div><br></div><div>For the generalization part, honestly, it just looks too complicated. I don&#39;t think this feature should require a chapter in the learn swift book to learn all the options - it should be a footnote. In Kyle&#39;s original proposal, one of the motivations for this feature is making the language easier to learn - calling super isn&#39;t natural for some beginners and having the compiler warn you when you&#39;re missing it is really helpful.</div><div><br></div><div>@plx: I think you bring up a great point with start and end. It may hint at a deeper problem as to how to define start and end. More code runs than the lines you write. There are retains and releases inserted by ARC, there are assembly instructions run, etc. I think your block examples give a great example of when this may be not desirable.</div><div><br></div><div>I think we have a good example of when not calling super can lead to bad bugs (viewDidAppear), but do we have an example of when calling super in the wrong place can lead to a bug? In most cases, does it matter?</div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Feb 18, 2016 at 7:02 AM plx via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>I think something like this making it into Swift at some point would be great, even if it’s just the `@requiresSuper` form; the positional variants would be even better.</div><div><br></div><div>However, I think any proposal like this will be *unusable* unless it *also* includes some way of explicitly marking a specific super-call as “OK, despite how it looks!”…and this is true even if you spec the feature out to only produce warnings, b/c even then you may want to silence those warnings at specific, “known-no-problem” call sites.</div><div><br></div><div>Here are two concrete examples:</div><div><br></div><div>// suppose `updateConstraints` has `@super(end)` applied to it:</div><div>override func updateConstraints() {</div><div>  // figure out where a bug is coming from:</div><div>  debugLog(“&lt;ISSUE 124&gt;#before constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)</div><div>  debugLog(“&lt;ISSUE 124&gt;#before constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)</div><div>  self.updateMyLocalConstraints()</div><div>  debugLog(“&lt;ISSUE 124&gt;#after constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)</div><div>  debugLog(“&lt;ISSUE 124&gt;#after constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)</div><div>  super.updateConstraints() // &lt;- not last call, but actually ok</div><div>  debugLog(“&lt;ISSUE 124&gt;#final constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)</div><div>  debugLog(“&lt;ISSUE 124&gt;#final constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)</div><div>}</div><div><br></div><div>// suppose `layoutSubviews` has `@super(begin)` applied to it:</div><div>override func layoutSubviews() {</div><div>  // capture timing info in debug runs:</div><div>  #if DEBUG</div><div>  self.performTimedBlock(“updateConstraints”) {</div><div>    super.layoutSubviews() // &lt;- not “first call”, but actually ok</div><div>    self.layoutMyCustomSubviews()</div><div>  }</div><div>  #else</div><div>  super.layoutSubviews()</div><div>  self.layoutMyCustomSubviews()</div><div>  #endif</div><div>}</div><div><br></div><div>…and I picked these because they’re examples where we are actually obeying the “spirit&quot; of the @super annotation.</div><div><br></div><div>Such an annotation could either be applied to the method (something like: `@force(@super(end):true)`?), or perhaps an annotation applied to the specific call-site…but right now, I don’t think Swift has anything at all that uses a &quot;call-site” attribute. </div><div><br></div><div>Are there any?</div></div><div style="word-wrap:break-word"><div><br></div><div><blockquote type="cite"><div>On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br><div><div style="word-wrap:break-word"><span><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The link to the original discussion is here: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html" target="_blank">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html</a></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall”</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">-Kyle</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"># Enforcing Calling Super</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">* Proposal: [SE-NNNN](<a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md" target="_blank">https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md</a>)</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">* Author(s): [Swift Developer](<a href="https://github.com/swiftdev" target="_blank">https://github.com/swiftdev</a>)</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">* Status: **Awaiting review**</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">* Review manager: TBD</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Introduction</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass&#39;s method in its overridden version at compile time. Also, it would optionally enforce that the superclass&#39;s version would be called before any other implementation in the method (similar to initialization rules). </span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Swift-evolution thread: [link to the discussion thread for that proposal](<a href="https://lists.swift.org/pipermail/swift-evolution" target="_blank">https://lists.swift.org/pipermail/swift-evolution</a>)</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Motivation</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don&#39;t, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift. </span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Currently, the only way this can be enforced is by commenting the superclass&#39;s code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn&#39;t look at the documentation for the method or even seasoned developers who simply overlooked this small detail. </span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Proposed solution</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method. </span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Detailed design</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br><br></span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">A possible implementation of this may look like this:</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">```</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">class MyClass {</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">    @requiredSuper func foo1() { }</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">    @requiredSuper(start) func foo2() { }</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">    @requiredSuper(end) func foo3() { }</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">}</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">```</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to: </span></div><ol style="margin-top:0pt;margin-bottom:0pt"><li dir="ltr" style="list-style-type:decimal;font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline"><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;vertical-align:baseline;white-space:pre-wrap">Overridden method must call the superclass’s implementation</span></div></li><li dir="ltr" style="list-style-type:decimal;font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline"><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;vertical-align:baseline;white-space:pre-wrap">Overridden method must call the superclass’s implementation as the first line of the method.</span></div></li><li dir="ltr" style="list-style-type:decimal;font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline"><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;vertical-align:baseline;white-space:pre-wrap">Overridden method must call the superclass’s implementation as the last line of the method.</span></div></li></ol><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">```</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">public class MyClass {</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">    @requiredSuper func foo() { }</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">}</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">```</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.</span></div><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Impact on existing code</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.</span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">## Alternatives considered</span></div><br><div style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.666666666666666px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">The alternative would simply be to not implement this feature.</span></div><br><br></span></div></span></div>_______________________________________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>