0

In the Laziness section of 'Effective Scala', it says:

Fields in scala are computed by need when val is prefixed with lazy. Because fields and methods are equivalent in Scala (lest the fields are private[this])

What does it mean by 'fields' and 'methods' being equivalent? Isn't it a rather strong statement?

dk14
  • 22,206
  • 4
  • 51
  • 88
Core_Dumped
  • 4,577
  • 11
  • 47
  • 71

3 Answers3

1

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).

Nader Ghanbari
  • 4,120
  • 1
  • 23
  • 26
1

Fields and methods are equivalent due to Uniform Access Principle:

All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation

See more info about how it's implemented in Scala.

P.S. UAP in Scala seems to be not completely implemented

Community
  • 1
  • 1
dk14
  • 22,206
  • 4
  • 51
  • 88
0

The main reason might be that, lazy val and def are computed before they are used (not when first defined).

The difference comes in as lazy val tries to avoid re-evaluations of an unchanging value, which has added cost of keeping the computed value in memory.

nitishagar
  • 9,038
  • 3
  • 28
  • 40