class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)
These lines of code outputs 12
, even though person.age=20
was successfully executed. I found that this happens because I used def in def person = new Person("Kumar",12)
. If I use var or val the output is 20
. I understand the default is val in scala. This:
def age = 30
age = 45
...gives a compilation error because it is a val by default. Why do the first set of lines above not work properly, and yet also don't error?
There are three ways of defining things in Scala:
def
defines a methodval
defines a fixed value (which cannot be modified)var
defines a variable (which can be modified)Looking at your code:
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: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:
what happens is that you first call the
person
method, and on the return value (an instance of classPerson
) you are changing theage
member variable.And the last line:
Here you are again calling the
person
method, which returns a new instance of classPerson
(withage
set to 12). It's the same as this: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 anew 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
is really what Scala intends to mean though. I don't really like to think that way at least...
With
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
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 reassignperson
with a new Person object likeI'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
Example, val
Example, var
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:
When the class is defined like:
and then instantiated with:
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:
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:
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.
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:
Another possibility would be:
However,
person.age=20
in your code is allowed, as you get back aPerson
instance from theperson
method, and on this instance you are allowed to change the value of avar
. The problem is, that after that line you have no more reference to that instance (as every call toperson
will produce a new instance).This is nothing special, you would have exactly the same behavior in Java:
Let's take this:
and rewrite it with equivalent code
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 theage_=
method (provided byvar
).