Protected methods on Final classes do not make much sense.
As you know, final (sealed in C#) classes are classes that cannot be derived. Therefore, it does not make sense to have protected methods on such classes, since the semantics of protected methods only come into play on derived classes (that are not possible on final classes, as mentioned above).
The class below has this problem:
final class MyClass
{
protected void foo() { ... }
}
Everything is fine, there is no damage done - Everything works as you would expect at runtime. It is just a little messy, since adding protected methods to final classes. This would indicate that some assumptions of the developer are wrong. Presumably the developer wanted, at some point, to be able to provide an overridden implementation of the method, but that is not possible because the class is final. The code makes promises that cannot be upheld.
The X++ compiler diagnoses the situation with a warning:
New protected method 'MyClass.foo()' declared in a final class.
<R>
{
for $c in /Class[@IsFinal='true']
for $m in $c/Method[@IsProtected='true']
return <ProtectedMethodsOnFinalClasses
Artifact='{$c/@Artifact}'
StartLine='{$m/@StartLine}' EndLine='{$m/@EndLine}'
StartCol='{$m/@StartCol}' EndCol='{$m/@EndCol}' />
}
</R>
One way of fixing is to make the method private, since there can be no methods overriding it. This would just be specifying the de facto semantics. However, you will not be able to do that if the method is derived from a protected one in a parent class, since restricting visibility is not possible.
Comments
-
IMO it makes sense to implement protected methods on final classes, when you want to expose an extension point. The protected method enables extension using CoC, so consumers can extend the otherwise sealed class by augmenting it. "Fixing" a protected method by making it private therefore comes a breaking change. The last time I checked it was not possible to make a private method wrappable, so implementing a protected method seems to be the only option, that I am familiar with.
-
Hey Peter, From a pure OO point of view you are right. However, X++ is an extensible language, and the design team decided to add default extensibility semantics to methods based on their access specifier. For example, protected methods are by default wrappable. Just like it is possible to create an [ExtensionOf] of a final class. Final on the class level is only restricting inheritance - not extension capabilities. Arguably it would have been cleaner that private methods could be marked as wrappable - but that was a design choice. As you write, "no damage is done". But I would discourage anyone from changing protected to private, as that is a breaking change, which could impact downstream consumers. See more here: learn.microsoft.com/.../extensibility-attributes
*This post is locked for comments