Skip to content

ALL-OVER0008 · final_method_overridden

Count members a base sealed against overriding that a subclass overrode anyway.

This is a deterministic rule for all languages. Read its implementation.

Read every member a base declares beside the declaration the subclass writes for it, and report an override of a member the base marked final. Sealing a member is the author saying the rest of the class depends on this exact behavior, so an override is not an extension, it is a hole punched through an invariant somebody wrote down on purpose. Whatever the sealed member guaranteed, the base still assumes, and the subclass no longer provides.

The marker and the override are almost never in the same file, so only a resolved inheritance chain can put them side by side, which is the whole reason this needs the graph.

Each finding names the subclass, the base, the sealed member, and the decorator that sealed it. The value is the number of sealed members overridden.

A subclass that restates the name as data rather than as a callable is judged by the hiding rule instead. A project that seals a member through a decorator of its own making rather than through final is not read, since the graph records the decorator a class wrote and not what that decorator means.

A type checker also reports this, and it is worth reporting twice, because the marker exists to be enforced and a project that runs no type checker still deserves the answer.

class Ledger:
@final
def balance(self):
return sum(self.entries)
class CachedLedger(Ledger):
def balance(self):
return self.total
class CachedLedger(Ledger):
def cached_balance(self):
return self.total
  • Generalizes Pylint W0239 overridden-final-method. Open reference
  • Cites “PEP 591, Adding a Final Qualifier to Typing”. Open reference
  • Cites “Effective Java”, design and document for inheritance or else prohibit it