26

I have

trait Invoker {
  val method: Method
}

Intellij IDEA code inspection is warning me that "Abstract value used in trait". Everything compiles fine. Is there something wrong with having an abstract value in a trait? If so, how should I specify that all extenders of the trait must define a method property?

Jonas
  • 121,568
  • 97
  • 310
  • 388
pondermatic
  • 6,453
  • 10
  • 48
  • 63
  • 2
    IntelliJ goes even step further and if you expand the tooltip over this warning you will find: "*Abstract values and variables in trait may cause errors during initialization.*" Sometimes these tooltips are even quoting Scala Lang. Spec. – Tomasz Nurkiewicz Oct 21 '11 at 07:15
  • 1
    If you are comfortable with abstract vals then you can go to Settings / Inspections / Scala / Abstract value in trait and turn down the warning level. – sourcedelica Oct 21 '11 at 12:30

2 Answers2

41

What is meant by this is the following weirdness:

trait A {
  val i: String
  def j: String
}

class C extends A {
  println ("val i = " + i)
  println ("def j = " + j)

  val i = "i"
  def j = "j"
}

val c = new C
// prints
// val i = null
// def j = j

So, as you can see i is initialised to it default value (null for AnyRef) before it is finally overridden by the constructor in C. (def declarations are re-referenced immediately.)

To avoid this one would have to put the val initialisations to the beginning of the constructor, if possible.


Additional weirdness (and how to solve it) in the following case

Consider

trait A {
  val i: String
  def j: String
}

abstract class D extends A {
  println ("val i = " + i)
  println ("def j = " + j)
}

class C extends D {
  val i = "i"
  def j = "j"
}
val c = new C
// prints
// val i = null
// def j = null

Now we seem to be out of luck; it looks as if there is no chance for us to initialise val i and def j before our superclass D tries to print them. In order to solve this problem, we must use Early definitions (§5.1.6 Scala reference):

class C extends {
  val i = "i"
  def j = "j"
} with D

val c = new C
// prints
// val i = i
// def j = j

And it works!

Debilski
  • 66,976
  • 12
  • 110
  • 133
  • Rather late comment, but since this is still being linked: the problem is _not_ the abstract `val`, but the implementation in `C`. If you change `i` in `A` to `def`, you'll get the same result. – Alexey Romanov May 18 '17 at 17:19
6

There are plenty of good reasons to use an abstract val in a trait. Unfortunately, IntelliJ IDEA does not distinguish those and simply warns against their use universally. In practice, this means that IntelliJ IDEA warnings are ignored.

Tony Morris
  • 3,045
  • 2
  • 29
  • 17
  • But the full warning message is fair. And after all it's a warning not a error. – pedrofurla Oct 10 '12 at 06:27
  • 3
    @pedrofurla: unavoidable warnings in correct code are an annoyance to good programmers, but a broken window invitation for weaker programmers to leave real problems in their code. It shouldn't be a warning. Tony is right that is far too opinionated for an IDE to be emitting warnings like this. See http://youtrack.jetbrains.com/issue/SCL-3651 for an issue to vote to fix this. – Alain O'Dea Oct 16 '12 at 02:56
  • 1
    Good programmers have to know how to interpret warnings. Errors in correct programs are an annoyance. – pedrofurla Oct 17 '12 at 10:25
  • I believe doing this backtrack in your head while you have other problems to tackle is a bit tedious. Supposingly we use scala because we favor simplicity. I will choose to enable this warning. – George Pligoropoulos Sep 02 '13 at 19:07