What does “fields and methods are equivalent” mean?

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?

Answers


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


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


Need Your Help

JSON not returning columns in Spring Data REST

json spring rest spring-data-jpa spring-data-rest

I am trying out examples for Spring Data REST however the JSON object returned in my testing does not return the column names (which were earlier 'PUT') and just returns the links to the objects. W...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.