Description
I totally understand that the old constant-inlining in Scala 2 has some problems, and that Scala 3 inline
is better. I also, agree that a final val
inside an object
or final class
is redundant.
However, unless I am missing something like a compiler bug or bad practice (and if that is the case I would highly appreciate the feedback), I think there are valid use cases for making a final val
.
I will share the situation in particular that we faced today, but I think the root use case is common enough.
// We have a trait defined in a third-party library.
// Which, among other things, defines a resources abstract method for users to override.
trait ExternalTrait {
protected type Resources
protected def resources: Resource[IO, Resources]
}
// And we want to define a custom trait in a company-internal library.
// Which, among other things, abstracts the initialization of the common resources our users need.
trait CompanyTrait extends ExternalTrait {
override protected final type Resources = CompanyResources
override protected final val resources: Resource[IO, Resources] = ...
}
// Finally, our users MUST not be able to override our setup.
final class UserClass extends CompanyTrait {
// resources is accessible here, but not modifiable.
}
This, of course, triggers thenoFinalVal
warning / error.
For now, we work around the problem using override protected final def
which is fine (and Arman will actually recommend doing that because of performance). But, we wonder if the rule is just too strict (since this feels like a normal use case in OOP) or if using final val
in this context is still problematic and thus should be avoided.