// code
object myClass extends Application {
abstract class AbsCell {
type T;
val init : T;
private var value : T = init;
def get : T = value;
def set(x : T): Unit = { value = x }
}
val cell = new AbsCell { type T = Int; val init = 1 }
cell.set(cell.get * 2)
println(cell.get) // added by me
}
// result
$ scalac myClassFilename.scala
$ scala myClass
0 // should't this be (1 * 2), it seems like init is never assigned
val cell = new{ type T = Int; val init = 1 } with AbsCell
I knew that this behavior existed for traits, but this is pretty unintuitive, to see automatic initialization of abstract values even in abstract classes...Thats really surprising to me - did the language change that much since
"Scalable Component Abstractions" by Odersky/Zenger was published in 2005
(because thats where this example was originally published, I guess)? That
seemed to be such a basic example to me, and I thought it was a for the
use of abstract type members.
I must admit I find your version less intuitive - is that the official
way to use abstract type members now? I find that kind of hard to
believe.
Thanks for your help.
Cheers
Thorsten
The language did change much, but not very much where this is concerned.
All that happened was the introduction of better initialization rules.
At the place where { // code } appears, it can depend on everything
before it having been initialized. Consider this:
val cell = newAbsCell { type T = Int; val x = get; val init = 1 }
val x = cell.x
What is the value of "x"? Should it execute "val init = 1" before "val
x = get"? And is "val x = get" supposed to be executed before or after
"private var value : T = init"? How can you tell which comes first?
Should Scala try to graph all possible initialization paths and figure
out a dependency tree to get things working? Mind you, newAbsCell
might well be in a JAR file, in a library. How could Scala split its
constructor so that its execution be staged in parts, with unknown
code being executed in between them? And how would that be ever be
compatible with Java and the JVM?
So things are simple: place the initialization where (when) you want
it to happen. After "newAbsCell", then it runs after that. Before it,
and it will run before.
It doesn't help much people who write convoluted code with abstract
member initialization and non-abstract member initialization depending
on abstract members, but it has the big merit of being simple, easy to
understand, and predictable.
--
Daniel C. Sobral
I travel to the future all the time.