What's the difference between:
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
and
class Person(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
Can I declare parameters as var
s, and change their values later? For instance,
class Person(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) {
println("happy " + n + " birthday")
n
}
}
For the first part the answer is scope:
If you prefix parameters with
val
,var
they will be visible from outside of class, otherwise, they will be private, as you can see in code above.And yes, you can change value of the var, just like usually.
You could use a
case class
and in that case thePerson
class would have those variables available outside of the class.case class Person(name: String, age: Int)
. Then the following code would work as expected.val z = new Person("John", 20); z.name //John
If you are familiar with Java, you can get the idea from this example:
is similiar to
While
is similar to
The intuition is that without var/val, the variable is only accessible inside the constructor. If var/val is added, the class will have the member variables with the same name.
The answers here are really good, however I'm tackling this one with exploring the byte code. When you apply
javap
on a class, it prints out package, protected, and public fields and methods of the classes passed. I created a class Person.scala and filled it out with the following code.After compiling the code with
scalac Person.scala
it generates three files with namesPerson.class, PersonVal.calass , PersonVar.cass
. By runningjavap
for each of these class files we can see how the structure would be:In this case it didn't create any class varible for Person since it is declared with neither val, nor val so name and age can just be used inside constructor.
In this case it has three members two for the input constructor and one for the member that we declared inside the constructore. However we don't have any setter for the input constructors so we can't change the values.
It's the same as PersonVal example but we can change the values in this case with those
variable_$eq
methods. it nothing just a shortened version ofvariable =
The answer by @Reza where the author explores byte code using javap helped me to clarify this concept the best. To cite a very specific example of this case please refer to below scenario that I faced in my production web app (Play + Scala): How to inject parameters into a class/trait method in Scala
If I don't use val prefix to injected parameter
authorizationHandler
then compiler throws this error:Sadly the error didn't help me to pinpoint to the correct issue which is to prefix with
val
.This
makes the fields available externally to users of the class e.g. you can later do
If you specify the args as
var
, then the scoping is the same as forval
, but the fields are mutable.