When overriding a concrete member or implementing an abstract one, use the
override
keyword.
This catches some scenarios where code would otherwise compile but misbehave at runtime.
Take the following trait, for example:
trait Foo[A] {
// Default implementation
def foo1(a: A): Int = 1
}
And now, an incorrect but valid implementation:
implicit val badFooInt: Foo[Int] = new Foo[Int] {
// Notice how this is not quite the right name.
def fool(i: Int) = 2
}
This compiles, but is clearly not what the we intended: we wanted to implement fool
but declared foo1
instead. Since fool
has a default implementation, this is valid but does not behave the way we think.
Had we used the override
keyword, however, the compiler would have caught our error:
implicit val fooInt: Foo[Int] = new Foo[Int] {
override def fool(i: Int) = 2
}
// error: method fool overrides nothing
// override def fool(i: Int) = 2
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another accepted practice is to never use override
unless required by the language.
This comes from the fact that, for a certain subset of the Scala community, overriding (in the sense of redefining an existing method) is a code smell: the compiler can check that you’re working with the right types, but not the invariants that are not expressed in the type system. A common example is implementing a Set
as a subtype of a Bag
(see Subtyping, Subclassing, and Trouble with OOP for an in-depth discussion).
Given that premise, the argument is that since overriding is bad, you should treat the use of the override
keyword like you would an instruction to silence compiler warnings: explicit acknowledgement that you’re doing something unsavoury.
This debate would be solved by adding a new implement
keywords, similar to override
but only used to flag members that you expect to implement abstract members in a superclass. This doesn’t exist however, and I feel the pragmatic approach is to follow the rule that catches bad programs rather than the purely ideological one.
Linter | Rule |
---|---|
WartRemover |