A def
pode ser implementado por um def
, um val
, um lazy val
ou um object
. Portanto, é a forma mais abstrata de definir um membro. Como as características são geralmente interfaces abstratas, dizer que você deseja val
é dizer como a implementação deve se comportar. Se você solicitar a val
, uma classe de implementação não poderá usar a def
.
A val
é necessário apenas se você precisar de um identificador estável, por exemplo, para um tipo dependente do caminho. Isso é algo que você geralmente não precisa.
Comparar:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) }
class F2(val bar: Int) extends Foo
object F3 extends Foo {
lazy val bar = {
Thread.sleep(5000)
42
}
}
Se você tinha
trait Foo { val bar: Int }
você não seria capaz de definir F1
ou F3
.
Ok, e para confundi-lo e responder @ om-nom-nom - usar abstract val
pode causar problemas de inicialização:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko
Este é um problema feio que, em minha opinião pessoal, deveria desaparecer nas futuras versões do Scala corrigindo-o no compilador, mas sim, atualmente esta também é uma razão pela qual não se deve usar val
s abstratos .
Editar (janeiro de 2016): Você tem permissão para substituir uma val
declaração abstrata por uma lazy val
implementação, de modo que também evite a falha de inicialização.