Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of def, val, and var in scala

Tags:

scala

People also ask

What is the difference between a VAR Def and Val in Scala?

In short, the val and var are evaluated when defined, while def is evaluated on call. Also, val defines a constant, a fixed value that cannot be modified once declared and assigned while var defines a variable, which can be modified or reassigned.

What does def mean in Scala?

def is the keyword you use to define a method, the method name is double , and the input parameter a has the type Int , which is Scala's integer data type. The body of the function is shown on the right side, and in this example it simply doubles the value of the input parameter a : def double(a: Int) = a * 2 -----

Is it OK to use VAR in Scala?

Even from a functional programming point of view, you can use vars (or mutable objects) locally, if they don't leave the scope where they are defined.

How do I assign a Val in Scala?

In Scala, reassignment to val is not allowed, but we can create a new val and assign the value to it. We can see an error when reassigning the values to a val . As a workaround, we can assign the result to a new val and use it.


There are three ways of defining things in Scala:

  • def defines a method
  • val defines a fixed value (which cannot be modified)
  • var defines a variable (which can be modified)

Looking at your code:

def person = new Person("Kumar",12)

This defines a new method called person. You can call this method only without () because it is defined as parameterless method. For empty-paren method, you can call it with or without '()'. If you simply write:

person

then you are calling this method (and if you don't assign the return value, it will just be discarded). In this line of code:

person.age = 20

what happens is that you first call the person method, and on the return value (an instance of class Person) you are changing the age member variable.

And the last line:

println(person.age)

Here you are again calling the person method, which returns a new instance of class Person (with age set to 12). It's the same as this:

println(person().age)

I'd start by the distinction that exists in Scala between def, val and var.

  • def - defines an immutable label for the right side content which is lazily evaluated - evaluate by name.

  • val - defines an immutable label for the right side content which is eagerly/immediately evaluated - evaluated by value.

  • var - defines a mutable variable, initially set to the evaluated right side content.

Example, def

scala> def something = 2 + 3 * 4 
something: Int
scala> something  // now it's evaluated, lazily upon usage
res30: Int = 14

Example, val

scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
somethingelse: Int = 17

Example, var

scala> var aVariable = 2 * 3
aVariable: Int = 6

scala> aVariable = 5
aVariable: Int = 5

According to above, labels from def and val cannot be reassigned, and in case of any attempt an error like the below one will be raised:

scala> something = 5 * 6
<console>:8: error: value something_= is not a member of object $iw
       something = 5 * 6
       ^

When the class is defined like:

scala> class Person(val name: String, var age: Int)
defined class Person

and then instantiated with:

scala> def personA = new Person("Tim", 25)
personA: Person

an immutable label is created for that specific instance of Person (i.e. 'personA'). Whenever the mutable field 'age' needs to be modified, such attempt fails:

scala> personA.age = 44
personA.age: Int = 25

as expected, 'age' is part of a non-mutable label. The correct way to work on this consists in using a mutable variable, like in the following example:

scala> var personB = new Person("Matt", 36)
personB: Person = Person@59cd11fe

scala> personB.age = 44
personB.age: Int = 44    // value re-assigned, as expected

as clear, from the mutable variable reference (i.e. 'personB') it is possible to modify the class mutable field 'age'.

I would still stress the fact that everything comes from the above stated difference, that has to be clear in mind of any Scala programmer.


With

def person = new Person("Kumar", 12) 

you are defining a function/lazy variable which always returns a new Person instance with name "Kumar" and age 12. This is totally valid and the compiler has no reason to complain. Calling person.age will return the age of this newly created Person instance, which is always 12.

When writing

person.age = 45

you assign a new value to the age property in class Person, which is valid since age is declared as var. The compiler will complain if you try to reassign person with a new Person object like

person = new Person("Steve", 13)  // Error

To provide another perspective, "def" in Scala means something that will be evaluated each time when it's used, while val is something that is evaluated immediately and only once. Here, the expression def person = new Person("Kumar",12) entails that whenever we use "person" we will get a new Person("Kumar",12) call. Therefore it's natural that the two "person.age" are non-related.

This is the way I understand Scala(probably in a more "functional" manner). I'm not sure if

def defines a method
val defines a fixed value (which cannot be modified)
var defines a variable (which can be modified)

is really what Scala intends to mean though. I don't really like to think that way at least...


As Kintaro already says, person is a method (because of def) and always returns a new Person instance. As you found out it would work if you change the method to a var or val:

val person = new Person("Kumar",12)

Another possibility would be:

def person = new Person("Kumar",12)
val p = person
p.age=20
println(p.age)

However, person.age=20 in your code is allowed, as you get back a Person instance from the person method, and on this instance you are allowed to change the value of a var. The problem is, that after that line you have no more reference to that instance (as every call to person will produce a new instance).

This is nothing special, you would have exactly the same behavior in Java:

class Person{ 
   public int age; 
   private String name;
   public Person(String name; int age) {
      this.name = name;  
      this.age = age;
   }
   public String name(){ return name; }
}

public Person person() { 
  return new Person("Kumar", 12); 
}

person().age = 20;
System.out.println(person().age); //--> 12

Let's take this:

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
person.age=20
println(person.age)

and rewrite it with equivalent code

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
(new Person("Kumar", 12)).age_=(20)
println((new Person("Kumar", 12)).age)

See, def is a method. It will execute each time it is called, and each time it will return (a) new Person("Kumar", 12). And these is no error in the "assignment" because it isn't really an assignment, but just a call to the age_= method (provided by var).