3
votes

In scala def is used to define a method and val, var are used for defining variables.

Consider the following code:

scala> def i = 3
i: Int

scala> i.getClass()
res0: Class[Int] = int

scala> val v = 2
v: Int = 2

scala> v.getClass()
res1: Class[Int] = int

scala> println(v)
2

scala> println(i)
3

scala> i+v
res4: Int = 5

scala> def o = () => 2+3
o: () => Int

scala> o.getClass()
res5: Class[_ <: () => Int] = class $$Lambda$1139/1753607449

Why does variable definition work using def? If it is defining a function that returns an Int then why does getClass show Int instead of a function object?

3

3 Answers

3
votes

Unlike val or var declaration, def i = 3 is not variable declaration. You are defining a method/function which returns a constant 3 and i does not take any parameters.

declaration using val and var get evaluated immediately but in case of lazy val and def evaluation happens when called explicitly.

i is a not argument function. In order to get rid of confusion you could declare it using empty parenthesis as well

def i() = 3

Difference between lazy val and def is

  1. lazy val is lazily evaluated and the result is cached. That means further

  2. def declaration is evaluated every time you call method name.

Example using Scala REPL

scala> lazy val a = { println("a evaluated"); 1}
a: Int = <lazy>

scala> def i = { println("i function evaluated"); 2}
i: Int

scala> a
a evaluated
res0: Int = 1

scala> a
res1: Int = 1

scala> a
res2: Int = 1

scala> i
i function evaluated
res3: Int = 2

scala> i
i function evaluated
res4: Int = 2

scala> i
i function evaluated
res5: Int = 2

Notice that a is evaluated only once and further invocations of a return the cached result i.e lazy val is evaluated once when it is called and the result is stored forever. So you see println output once

Notice function is evaluated every time it is invoked. In this case you see println output every time you invoke the function

General Convention

There's a convention of using an empty parameter list when the method has side effects and leaving them off when its pure.

edited

scala> def i = 1
i: Int

scala> :type i
Int

scala> :type i _
() => Int
2
votes

EDIT: My answer addresses the question of revision #3.

It is quite useful to look on the code in the middle of the compilation process where you can look on what your code is actually translated to. The following simple program:

object TestApp {
    def definedVal = 3
    val valVal = 3
    lazy val lazyValVal = 3

    def main(args: Array[String]) {
        println(definedVal)
        println(valVal)
        println(lazyValVal)
    }
} 

is translated to the following (using -Xprint:mixin compiler option):

[[syntax trees at end of                     mixin]] // test.scala
package <empty> {
  object TestApp extends Object {
    @volatile private[this] var bitmap$0: Boolean = false;
    private def lazyValVal$lzycompute(): Int = {
      {
        TestApp.this.synchronized({
          if (TestApp.this.bitmap$0.unary_!())
            {
              TestApp.this.lazyValVal = 3;
              TestApp.this.bitmap$0 = true;
              ()
            };
          scala.runtime.BoxedUnit.UNIT
        });
        ()
      };
      TestApp.this.lazyValVal
    };

    def definedVal(): Int = 3;

    private[this] val valVal: Int = _;
    <stable> <accessor> def valVal(): Int = TestApp.this.valVal;

    lazy private[this] var lazyValVal: Int = _;
    <stable> <accessor> lazy def lazyValVal(): Int = if (TestApp.this.bitmap$0.unary_!())
      TestApp.this.lazyValVal$lzycompute()
    else
      TestApp.this.lazyValVal;

    def main(args: Array[String]): Unit = {
      scala.this.Predef.println(scala.Int.box(TestApp.this.definedVal()));
      scala.this.Predef.println(scala.Int.box(TestApp.this.valVal()));
      scala.this.Predef.println(scala.Int.box(TestApp.this.lazyValVal()))
    };
    def <init>(): TestApp.type = {
      TestApp.super.<init>();
      TestApp.this.valVal = 3;
      ()
    }
  }
}

From the output above it is possible to conclude the following:

  1. definedVal is actually a method.
  2. valVal is a field which is initialized in the constructor and has an automatically generated accessor.
  3. For the lazy field lazyValVal compiler generates compute method which is called only once when the field is accessed the first time.
-1
votes

There is few different concept. Call by name, call by value and call by need. All def is essentially calls by name. What do you mean variable definition using def ?? Looks like duplicate to me: Call by name vs call by value in Scala, clarification needed More details in wiki: https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name