4

I define a class with abstract type as follow:

abstract class AbsCell2{
    type T
    val init: T
    private var value: T = {
         println("Hello "+init);
         init
    }
    def get : T = value
    def set(x : T) = { value = x}
}

Now I instantiate an object with type Int

scala> val cell = new AbsCell2{type T = Int ; val init = 10}
Hello 0
cell: AbsCell2{type T = Int} = $anon$1@969ebb

Pay attention to the output from println. It seams the variable init hasn't been initialized as 10. Note that the version of scala is 2.9.0-1

爱国者
  • 4,298
  • 9
  • 47
  • 66
  • This example is borrowed from the presentation provided by Martin Ordersky. http://lampwww.epfl.ch/~odersky/ – 爱国者 Aug 14 '11 at 07:34
  • 1
    But now execute `cell.init` in the REPL and it _will_ show you 10. Is your question about why it doesn't print 10 before the object is initialized? – Ray Toal Aug 14 '11 at 07:42
  • I think 爱国者 is also asking why `cell.get` returns 0, and how to get it to return 10. – Kipton Barros Aug 14 '11 at 07:47
  • But when you call cell.get after the object is created , it split out 0. If you call cell.set(20), then cell.get, it print out 20 – 爱国者 Aug 14 '11 at 07:48

3 Answers3

4

I think you're looking for Scala's early initializers,

scala> val cell = new {type T = Int ; val init = 10} with AbsCell2
Hello 10
cell: AbsCell2{val init: Int; type T = Int} = $anon$1@1efa9557

scala> cell.get
res0: cell.T = 10

Early initializers allow you to allocate a new object and set some specific fields before the class constructor runs. In this case, since value depends on init, we use the early initializer syntax (new { val init = ... } with AbsCell2) to first set init so that the class constructor can properly initialize value.

See also this question: In Scala, what is an "early initializer"?

Community
  • 1
  • 1
Kipton Barros
  • 21,002
  • 4
  • 67
  • 80
0

For question about difference between new { type T = Int ; val init = 10 } with AbsCell2 and new AbsCell2 { type T = Int ; val init = 10 }

The first one is the so-called early-initializers or pre-initialized fields(mentioned in Abstract Members chapter in Programming In Scala)。It allows the subclass to initialize fields before the super class is called。 In this case, init has already been set as 10 before the initialization of AbsCell2。

The latter one is normal inheritance, it creates an anonymous class then extends AbsCell2, just like:

 class AbsCell' extends AbsCell {
    type T = Int 
    val init = 10 
 }

However, the anonymous class gets initialized after the abstract class AbsCell2, so init are not available in the initialization of itself, namely, init is the default value of the Type, 0 in this case. Therefore, you get 0 in the print。

use scalac -Xprint:all Test.scala, you will see the following:

 abstract class AbsCell2 extends Object {
    <stable> <accessor> def init(): Object;
    ....
   def <init>(): AbsCell2 = {
    AbsCell2.super.<init>();
    AbsCell2.this.value = {
      scala.this.Predef.println("Hello ".+(AbsCell2.this.init()));
      AbsCell2.this.init()
    };
    ()
   }
 };

 // normal initialization
 final class anon$1 extends AbsCell2 {
    private[this] val init: Int = _;
    <stable> <accessor> def init(): Int = anon$1.this.init;
    ....
    def <init>(): <$anon: AbsCell2> = {
     anon$1.super.<init>();
     anon$1.this.init = 10;
     ()
   }
 };

 // early initialization
 final class anon$2 extends AbsCell2 {
   private[this] val init: Int = _;
   <stable> <accessor> def init(): Int = anon$2.this.init;
   ....
   def <init>(): <$anon: AbsCell2> = {
     val init: Int = 10;
     anon$2.this.init = init;
     anon$2.super.<init>();
     ()
   }
 }

From the code, we can see that for normal initialization, init is set to 3 after the initialization of super class AbsCell2, when AbsCell2.this.init() gets invoked, it actually refers to the subclass' init field and 3 is yet to set, so we get the default type value。On the contrary, early initialization first set init to 3 then call super class initialization。

Allen Chou
  • 1,229
  • 1
  • 9
  • 12
0

Change from val to def:

abstract class AbsCell2{
  type T
  def init: T
  private var value: T = {
     println("Hello "+init);
     init
  }
  def get : T = value
  def set(x : T) = { value = x}
}

It works as expected:

scala> val cell = new AbsCell2{type T = Int ; def init = 10}
Hello 10
cell: AbsCell2{type T = Int} = $anon$1@4302df5
Wojciech Durczyński
  • 2,627
  • 2
  • 16
  • 11