ChatGPT解决这个技术问题 Extra ChatGPT

Use of def, val, and var in scala

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?


Y
Ying

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)

To confuse things, the internal state of a val can be changed but the object referred to by a val cannot. A val is not a constant.
To further confuse things, val (and maybe var as well, I haven't tried it) can be used to define a function. When using def to define a function/method the body of the def is evaluated every time it is called. When using val it is evaluated only at the point of definition. See stackoverflow.com/questions/18887264/…
@melston Yes, but a method and a function are also not exactly the same thing.
to even further confuse things, def can also be used to define member variables of a class, not necessarily to use var.
@pferrel not really confusing. Same as with Java's final. You can mark a List as final, but could modify its contents.
P
Paolo Maresca

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.


I do not think the above explanation is correct. See the other answers.
@PerMildner Can you please elaborate on what is wrong in the above answer?
I do not remember what my original complaint was. However, the last part of the answer, about personA et al. seems off. Whether modifying the age member works or not is independent of whether you use def personA or var personB. The difference is that in the def personA case you are modifying the Person-instance returned from your first evaluation of personA. This instance is modified, but it is not what is returned when you once again evaluate personA. Instead, the second time you do personA.age you are effectively doing new Person("Tim",25).age.
K
Kintaro

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

Yes. This point can easily be demonstrated by calling the hashCode method on the personA
x
xji

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


L
Landei

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

D
Daniel C. Sobral

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


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now