Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need some help with Scala's instance variables

Assume this Java code:

public class A {
   public A(String g) {
      x += g.length();
   }

   private int x = 0;
}

If I create an instance of A, like this:

A a = new A("geo");

after this call, the value of x will be 3. What am I doing wrong in my Scala code?

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

object x extends Application {
  val x = new A("geo")
  println(x.x)
}

This prints 0. I assumed that when the compiler reaches the var x:Int = 0, the body of the main constructor has ended. Am I wrong? How else could you declare instance variables in Scala ( assuming I don't want them in my constructor ) ?

like image 407
Geo Avatar asked Dec 16 '09 19:12

Geo


3 Answers

Keep in mind that your code translates into something similar (but not exactly) to this:

public class A {

  private final String g;
  private int x;

  public A(String g) {
    this.g = g;
    x_$eq(x() + g.length());
    x = 0;
  }

  public void x_$eq(int arg0) {
    x = arg0;
  }

  public int x() {
    return x;
  }

  public String g() {
    return g;
  }
}

But vars defined in (non-constructor) methods get translated into actual local variables.

Not sure if this explains the reasoning so much as highlights one of the differences.


EDIT - Changed "translation" from scala to java for clarity and ability to more accurately represent what is happening.

like image 168
Mitch Blevins Avatar answered Sep 30 '22 04:09

Mitch Blevins


Your confusion results from a misunderstanding of how constructors in Scala works. Specifically, let's translate the Scala code you posted into Java:

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

becomes

public class A {
   public A(String g) {
      x += g.length();
      x = 0;
   }
   private int x;
}

The reason is simple. The whole body of a class in Scala is the primary constructor for that class. That means the statements in it, and initializing val and var are statements, will be executed in the order they are found.

PS: Here is the actual, true rendition of that code.

Scala 2.7

C:\Users\Daniel\Documents\Scala\Programas> scalac -print A.scala
[[syntax trees at end of cleanup]]// Scala source: A.scala
package <empty> {
  class A extends java.lang.Object with ScalaObject {
    @remote def $tag(): Int = scala.ScalaObject$class.$tag(A.this);
    <paramaccessor> private[this] val g: java.lang.String = _;
    <stable> <accessor> <paramaccessor> def g(): java.lang.String = A.this.g;
    private[this] var x: Int = _;
    <accessor> def x(): Int = A.this.x;
    <accessor> def x_=(x$1: Int): Unit = A.this.x = x$1;
    def this(g: java.lang.String): A = {
      A.this.g = g;
      A.super.this();
      A.this.x_=(A.this.x().+(g.length()));
      A.this.x = 0;
      ()
    }
  }
}

Scala 2.8

C:\Users\Daniel\Documents\Scala\Programas>scalac -print A.scala
[[syntax trees at end of cleanup]]// Scala source: A.scala
package <empty> {
  class A extends java.lang.Object with ScalaObject {
    <paramaccessor> private[this] val g: java.lang.String = _;
    <stable> <accessor> <paramaccessor> def g(): java.lang.String = A.this.g;
    private[this] var x: Int = _;
    <accessor> def x(): Int = A.this.x;
    <accessor> def x_=(x$1: Int): Unit = A.this.x = x$1;
    def this(g: java.lang.String): A = {
      A.this.g = g;
      A.super.this();
      A.this.x_=(A.this.x().+(g.length()));
      A.this.x = 0;
      ()
    }
  }
}
like image 33
Daniel C. Sobral Avatar answered Sep 30 '22 06:09

Daniel C. Sobral


Change this:

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

to

class A(val g:String) {
  var x = g.length

}
like image 37
Jim Barrows Avatar answered Sep 30 '22 05:09

Jim Barrows