Well it simply means that you can define an abstract val by a def and an abstract def by a val.
For example
trait Server {
def port:Int
}
has an abstract function, namely port. You can for sure implement (or define or override) this with a def, like this
object DefaultServer extends Server {
override def port: Int = 80
}
But in this case every access to port will cause a function application (or a method call) which is simply unnecessary. For this simple reason Scala gives us the possibility of implementing the abstract def with a value:
object DefaultServer extends Server {
override val port: Int = 80
}
The same applies to abstract values. You can define abstract values with the same syntax:
trait Server {
val port: Int
}
And you can override them with a def:
object DefaultServer extends Server {
override def port: Int = 80
}
Stability
You may wonder what will happen if you override an abstract val with a def which gives you a different value each time you call it. Will you get the first computed value because the item is a val or you will get a different value each time you call it because the actual implementation is a def.
For example:
object DefaultServer extends Server {
override def port: Int = scala.util.Random.nextInt()
}
Fortunately Scala compiler detects this and throws the following error:
error: overriding value a in trait Server of type Int;
method a needs to be a stable, immutable value
override def port:Int = scala.util.Random.nextInt()
Laziness
When it comes to laziness this uniform behavior (treating fields and methods in the same way) is very useful.
First note that a lazy abstract value does not exist, i.e. you can not define an abstract val as lazy.
Implementing an abstract def by a lazy val, on the other hand, is perfectly legal and useful. The lazy value will be computed only on the first call and memoized (cached and used for future calls).