The following Scala class shows four possibilities for constructor parameters (3 different declarations, one of which has two effects):
class ConstructorParams (local:Int, prvt:Int, val readonly:Int, var writable:Int) {
def succ_prvt() = prvt + 1
}
- The first parameter,
local, isn't referenced by any methods. It exists only as a local variable within the constructor (it could be referenced by field initialisers without changing this; try adding val foo = local to the constructor).
- The second,
prvt, is referenced by a method, so it becomes a private field.
- The
val declarator on the third creates a getter and a private backing field.
- The
var declarator on the fourth creates both a getter and a setter, as well as a private backing field.
In particular, note that a constructor parameter without a val or var declarator is private (which is a matter of accessibility) only if it's referenced in a function within the class; otherwise, it's local (which is a matter of scope).
Technically, the last three parameters exist as local values as well as private fields (initialized to the local values), but this distinction shouldn't come up much, so you can mostly put it out of your mind.
def as a parameter declarator doesn't make much sense as it's used to introduce a new function, not to declare a value/variable name; it also isn't used for function parameters (constructor parameters are closely related to function parameters). Since functions are a first class, you use a function type, rather than a special declarator, to declare that a parameter holds a function.
Printing out what the compiler makes of ConstructorParams by passing -Xprint:constructors to the compiler, we get (with comments added):
class ConstructorParams extends Object {
/* 2nd (no-declarator) param becomes private field due to reference in `succ_prvt()` */
<paramaccessor> private[this] val prvt: Int = _;
/* `val` becomes private field + getter */
<paramaccessor> private[this] val readonly: Int = _;
<stable> <accessor> <paramaccessor> def readonly(): Int = ConstructorParams.this.readonly;
/* `var` becomes private field + getter + setter */
<paramaccessor> private[this] var writable: Int = _;
<accessor> <paramaccessor> def writable(): Int = ConstructorParams.this.writable;
<accessor> <paramaccessor> def writable_=(x$1: Int): Unit = ConstructorParams.this.writable = x$1;
/* causes `prvt` constructor param to become private field */
def succ_prvt(): Int = ConstructorParams.this.prvt.+(1);
def <init>(local: Int, prvt: Int, readonly: Int, writable: Int): ConstructorParams = {
ConstructorParams.this.prvt = prvt;
ConstructorParams.this.readonly = readonly;
ConstructorParams.this.writable = writable;
ConstructorParams.super.<init>();
()
}
}
The above example class compiles to the Java equivalent of:
public class ConstructorParams {
/* 2nd (no-declarator) param becomes private field due to reference in `succ_prvt()` */
private final int prvt;
public int succ_prvt() {
return this.prvt + 1;
}
/* `val` becomes private field + getter */
private final int readonly;
public int readonly() { return this.readonly; }
/* `var` becomes private field + getter + setter */
private int writable;
public int writable() { return this.writable; }
public void writable_$eq(int x$1) {
this.writable = x$1;
}
/* 1st param is local, since it's not referenced in any other methods */
public ConstructorParams(int local, int prvt, int readonly, int writable) {
/* parent constructor is invoked implicitly, so not repeated here */
this.prvt = prvt;
this.readonly = readonly;
this.writable = writable;
}
}
If you use javap on ConstructorParams (as Brian did) with the -p argument, you'll see a class signature equivalent to the one in the above Java source.