13

What can I use the private final modifier in Scala for?

Given the below code:

1| class A { def callFoo = foo; private final def foo = "bar of A" }
2| class B extends A { private final def foo = "bar of B"}
3| println((new A()).callFoo)
4| println((new B()).callFoo)

Line 3 and 4 prints:

1| bar of A
2| bar of A

It is understandable why line 2 doesn't print bar of B because there are actually two foo definitions and the latter in B doesn't override the former in A. Otherwise Scala would require the override- instead of the final modifier.

So why does Scala not simply forbid the combination of the modifiers private final?

Tim Friske
  • 2,012
  • 1
  • 18
  • 28

3 Answers3

15

Ok, this is tricky. Your question: "So why does Scala not simply forbid the combination of the modifiers private final?" is based on the assumption that this combination has no use.

Let's say you are right (and you are, except for a tiny detail, which will be mentioned later). I'm not a compiler guy, but from my point of view "simply forbid" is probably not that simple at all (at least in this case). And why would someone attempt to do it? What are the trade-offs? Only because something is not useful does not necessarily mean that it does any harm. Just don't use it...

Now here comes the tiny detail you seem to have overlooked. The private modifier is a visibility modifier, which means class B is unaware of it's existence. But Scala's visibility modifiers are a bit more complex, than say, Java's. Let's assume that for whatever reason you would require code shown in the following code snippet, the compiler will not allow it.

package scope

class A {
  def callFoo = foo;
  private[scope] final def foo = "bar of A"
}
class B extends A {
  private[scope] final def foo = "bar of B"
}

object Main extends App {
  println((new A()).callFoo)
  println((new B()).callFoo)
}

This is one of the errors provided by the compiler: "method foo cannot override final member".

So here you go. Scala simply forbids this combination ;)

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
agilesteel
  • 16,775
  • 6
  • 44
  • 55
  • I didn't thought about the additional scope a modifier can have. You are right, having a package private definition, `final` prohibits overriding it. In this case it has a use. But otherwise I think a language construct without an effect must not be legal. Here, if `final` doesn't prevent subclasses or traits from overriding a definition than it must not be used in a declaration. – Tim Friske Sep 06 '11 at 12:55
  • @Tim the reason `final` doesn't prevent subclasses / traits overriding the definition is because `private` has already prevented that. `private` members are not visible to subclasses so there is nothing to override. For this to be a problem, you the programmer would have to make two distinct errors: 1) trying to override a private method, and 2) forgetting to use the `override` keyword. It's the same in Java except Java is more error-prone since the `@Override` annotation is optional. – Luigi Plinge Sep 06 '11 at 13:46
4

Addressing the wider question,

So why does Scala not simply forbid the combination of the modifiers private final?

That's a new rule, and, at that, a new exception. It makes the language more complex, and at absolutely no gain. Why make things more complicated for no good reason?

That's the kind of thing Java does which Odersky dislikes a lot. For the language to become more complex, there must be some gain.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 2
    The language might become more complex for the parser/compiler because it needs to be aware of that exception. But from the user perspective I think it is easier when one is being guided by the compiler. Another example would be the `abstract trait A` vs. `trait A`. What is the use to explicitly state that a particular trait is `abstract` when this is true for all traits. – Tim Friske Sep 06 '11 at 14:08
  • @Tim You don't consider it necessary for a user to _learn_ the _whole_ language? After all, it is not just the compiler that must support the rule -- the programmer must learn it as well. – Daniel C. Sobral Sep 06 '11 at 14:11
3

I initially thought it was to prevent overriding private methods in nested classes, but apparently not:

class A {
  private final def foo = 0

  class B extends A {
    override def foo = 1
  }
}

error: method foo overrides nothing
           override def foo = 1
                        ^

Perhaps it's just to simplify refactoring? So if you have a final method, try to make it private, and find you need it not to be private after all, you won't lose finality in the process?

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487