An SO User
An SO User

Reputation: 25028

How are default constructors's arguments turned into fields?

I am running simple code in Scala REPL that creates two classes with a single Int value x. Here's how:

scala> class C(x: Int){}
defined class C

scala> new C(100).x
<console>:13: error: value x is not a member of C
       new C(100).x
                  ^

scala> class D(val x: Int){}
defined class D

scala> new D(100).x
res1: Int = 100 

My understanding was that for class C the variable x would become a mutable variable (var by default) and for class D an immutable variable. However, I have run into this issue where x isn't a member of C.

How so?

Upvotes: 1

Views: 78

Answers (2)

λ Allquantor λ
λ Allquantor λ

Reputation: 1131

To research this question we can reverse engineer to see "what would the compiler do?" :)

For that, we are compiling the class C.scala with the content class C(x: Int){} by running:

scalac C.scala

this, generates C.class. Now, we can use the java class disassembler javap to see what the compiler would generate.

running javap -p C.class would produce:

public class C {
  public C(int);
}

if we are repeating the whole procedure with class D(val x: Int){} we would yield:

public class D {
  private final int x;
  public int x();
  public D(int);
}

We can see that the difference is that the keyword val is telling the class to create a getter method.

Coming back to your assumption that without the val keyword the class variable would be defined as mutable: this is wrong. To prove that we can go one level deeper into the disassembling. By running:

javap -p -v C.class

we get (among a lot of other information) this snippet :

{
  public C(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: aload_0
         1: invokespecial #14                 // Method java/lang/Object."<init>":()V
         4: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LC;
            0       5     1     x   I
      LineNumberTable:
        line 4: 0
        line 2: 4
    MethodParameters:
      Name                           Flags
      x                              final
}

you can clearly see that the class variable x is still declared as final and thus, immutable.

Upvotes: 3

Nikola Stojiljkovic
Nikola Stojiljkovic

Reputation: 693

Attributes in Scala classes can have the following modifiers:

  • val makes the attribute immutable; it's always public - this makes sense since the value can't be changed
  • var makes the attribute mutable and public
  • no modifiers makes the attribute mutable and private

Code examples:

// no modifier
class A(x: Int) {
  def print() = {
    x += 1 // this i fine, it's mutable
    println(x)
  }
}

val a = new A(3)
// a.x - compile error, it's private


// var
class A(var x: Int) {
  def print() = {
    x += 1 // this is fine, it's mutable
    println(x)
  }
}

    val a = new A(3)
    a.x // you can do this since it's public (modifier var)

// val
class A(val x: Int) {
  def print() = {
    // x += 1 // can't do this, it's immutable
    println(x)
  }
}

val a = new A(3)
a.x // you can do this since it's public (modifier val)

More about constructors and classes: http://joelabrahamsson.com/learning-scala-part-four-classes-and-constructors/

Upvotes: 1

Related Questions