1

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?

An SO User
  • 24,612
  • 35
  • 133
  • 221

2 Answers2

3

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.

λ Allquantor λ
  • 1,071
  • 1
  • 9
  • 22
1

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/

Nikola Stojiljkovic
  • 693
  • 1
  • 5
  • 11
  • 2
    All 3 claims in the first paragraph are wrong: `val` and `var` aren't always public, that's just the default; without modifiers you may or may not have a field (it depends on whether the parameter is used in any methods), but it'll be immutable at any rate. – Alexey Romanov Dec 15 '16 at 14:12
  • I agree that they are not always public; you could use `private` modified, but I think the point of the answer is still there, that in this case they are public by default. I could edit the answer though. I'm open to edit suggestions. Regarding the methods, I am not sure I understood that completely. What is the example when you would use something like `class A(val t: Int)` and `t` would be an attribute / field of the class? – Nikola Stojiljkovic Dec 15 '16 at 14:49
  • When you have `class A(i: Int)`, class `A` has no field for `i`; `i` is just a (immutable) constructor parameter. When you have `class A(i: Int) { def foo = i }`, class `A` has a private immutable field for `i`. – Jasper-M Dec 15 '16 at 14:58
  • I see, thanks. Just read the answer here: http://stackoverflow.com/questions/14694712/do-scala-constructor-parameters-default-to-private-val. Although the focus of my answer was on the attribute being immutable and public, rather than being generated as a field. I'm not honestly sure how important is that, but maybe I should change the `makes the attribute` bit – Nikola Stojiljkovic Dec 15 '16 at 15:01