4

In scala, there are four kinds of member modifier, i.e. def, val, lazy val, var. There is a seemingly complicated and inconsistent set of rules regarding overriding, for instance, def can be overridden by val, while not the other way around. It would be great to see a full list of all these rules.

Anton Dozortsev
  • 4,782
  • 5
  • 34
  • 69
Lifu Huang
  • 11,930
  • 14
  • 55
  • 77
  • 1
    The underlying principle is that you can't loosen a superclass's contract in a subclass. `val` can override `def` because it doesn't break any promise `def` made, but `val` promises to return the same value every time, so you can't override with `def` which might return something different each time. – Seth Tisue Oct 15 '16 at 18:56
  • @SethTisue Thanks, this is indeed one of the major principles. But IMHO, it seems that this cannot explains everything. For instance, Why cannot a concrete `var` be overridden by another `var` while `val` can be overridden by `val`? Why `var` cannot be overridden by `def` since `var` can be seen as a pair of `def`(read and write)? (some discussion here http://stackoverflow.com/questions/27623074/why-its-impossible-to-override-var-with-def-in-scala) – Lifu Huang Oct 16 '16 at 01:36
  • re: two `def`s together teaming up together to override one `var`, I think that's covered by the principle I stated — `var` has a certain semantics you can rely on, but those `def`s could be doing anything. re `var` overriding `var`, I don't know about that one. Would it be useful to do so? – Seth Tisue Oct 16 '16 at 17:31
  • @SethTisue Thank you for your explanation, that make sense to me. – Lifu Huang Oct 17 '16 at 00:38

2 Answers2

14

All overridings in scala fall into two categories, the first case is to override an abstract member(in trait or abstract class) and the other is to override a concrete member:

Override concrete members

def, val, lazy val, var might all be overridden in subclasses:

  1. def: can be overridden by all kinds of members(def, val, lazy val, and var).

  2. val: can only be overridden by val.

  3. lazy val: can only be overridden by lazy val.

  4. var: a concrete var cannot be overridden.

Override abstract members

lazy val cannot be abstract, so there are only three rules:

  1. def: can be overridden by all kinds of members(def, val, lazy val, and var).

  2. val: can be overridden by val and lazy val.

  3. var: can be overridden by (1) var, or (2) a pair of read and write operations implemented by def, val, or lazy val.

EDITED:

As pointed out by @iuriisusuk, please refer to the related section in spec for a formal description.

Community
  • 1
  • 1
Lifu Huang
  • 11,930
  • 14
  • 55
  • 77
  • 3
    To make this a perfect answer, you would not only rely on experiments, but also check out if the Scala language spec has to way. You see - experiments can depend on versions and local setups. – GhostCat Oct 15 '16 at 09:27
  • 1
    @GhostCat, thanks for your suggestion, the reason why I experiment is exactly that I have not yet found any organized rules in official documents or even blogs. I will edit my answer if I find them. Please also let me know if you have any good resource about this topic :) – Lifu Huang Oct 15 '16 at 09:31
  • `lazy val` can appear in a trait. Do you mean it can't be abstract? – Alexey Romanov Oct 15 '16 at 13:05
  • 2
    @LifuHuang here is a link that formally describes most of the thing you have mentioned, like overriding and modifiers http://scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html. The only minus is that it's a lot =) – iuriisusuk Oct 15 '16 at 13:49
  • @iuriisusuk, thanks. I have attach the link in my answer for reference. And yes, I think it might be too formal and scattered for gaining an insight from. – Lifu Huang Oct 15 '16 at 14:07
  • Maybe you could inline my answer (what the spec says). I think it's simpler than a grid. Maybe explain the rules better? – som-snytt Oct 17 '16 at 05:04
  • @som-snytt Thank you for your fantastic answer. Since your answer has already been a complete and excellent answer in its own right, why not just leave both answers there. Your answer gives the consistent principles behind the rules, and my "grid" gives supporting experiment results(stays on the surface, but might be useful). And let the readers take whatever they need :) – Lifu Huang Oct 20 '16 at 11:59
2

The two rules from the spec are:

  • "A stable member can only be overridden by a stable member."
  • lazy val must be overridden by lazy val.

The restriction, that vars can't override vars, is because they didn't want to emit two fields for the two vars. Also this question.

Community
  • 1
  • 1
som-snytt
  • 39,429
  • 2
  • 47
  • 129