Reputation: 29537
New to Scala and no matter how many articles/tutorials I read (like these | three | ones) I can't seem to wrap my brain around how constructors work.
Let's take three examples of a primary constructor here:
// 1
class Fizz(buzz : Buzz) { ... }
// 2
class Fizz (val buzz : Buzz) { ... }
// 3
class Fizz (var buzz : Buzz) { ... }
For each of these:
buzz
property created?
buzz
field created?
Upvotes: 3
Views: 1343
Reputation: 4595
Constructors are actually a pretty wild beast in Scala. In fact the Scala compiler is able to make some smart choices for you.
By the phrasing of your question, I take it you probably have some experience with Java. To make it perfectly clear what's happening - and allow you to experiment yourself in the future - let's decompile the code that the Scala compiler produces so we can see the Java equivalent. For conciseness, I'll only show the declarations of the methods/fields, and not their implementation.
buzz
used only in constructorclass Fizz(buzz : Buzz)
Will compile to the Java equivalent of
public class Fizz {
public Fizz(Buzz);
}
Since Fizz
doesn't declare any method/field referencing buzz
(apart from the constructor itself), Scala will not create any field/method for it.
buzz
referenced outside the constructorclass Fizz(buzz : Buzz) {
def foo: Buzz = buzz
}
This time buzz
is used by the foo
method, and so the compiler has to store it as a field. Since the field was not declared a var
, it will be made private final
.
public class Fizz {
private final Buzz buzz;
public Buzz foo();
public Fizz(Buzz);
}
val
qualifierclass Fizz(val buzz : Buzz)
This time, you explicitly said you wanted buzz
to be a val
. This will have the effect of creating a private final
field to hold buzz
, and a public method of the same to access it.
public class Fizz {
private final Buzz buzz;
public Buzz buzz();
public Fizz(Buzz);
}
var
qualifierclass Fizz(var buzz : Buzz)
This case is very similar to the previous one, except that now you're specifying that you want to be able to modify buzz
. This will cause the Scala compiler to provide a setter method for you, under the funny name of buzz_$eq
. The $
shenanigan is only required because of JVM constraints in naming methods. In your Scala code, this method will appear as buzz_=
and syntactic sugar will allow you to call it as fizz.buzz = someBuzz
. This way, it actually looks as if you're mutating as field, but you're really only calling a setter.
public class Fizz {
private Buzz buzz;
public Buzz buzz();
public void buzz_$eq(Buzz);
public Fizz(Buzz);
}
These commands are helpful when investigating that kind of issue:
scalac Fizz.scala
will create a compiled Fizz.class
that is not human-readable. You can decompile it into a Java version using
javap -constants -p Fizz
while in the directory containing Fizz.class
Upvotes: 7
Reputation: 30157
In all the cases you showed the fields are also parameters for the constructor.
The parameters declared to be either val or var become public members. If you use the variables in the constructor they will not become members, if you use them in the class, they will be private members.
In first case class Fizz(buzz : Buzz){}
the buzz
parameter is immutable and not become member (I assume you don't use it anywhere).
In second case class Fizz (val buzz : Buzz) {}
the buzz
parameter is immutable and become public member.
In third case class Fizz (var buzz : Buzz) {}
the buzz
parameter is mutable and become public member.
And again in all the cases there isn't any getter or setter created automatically.
Upvotes: 0