First, some modifications to your code (see below). I dropped the case
as it is not relevant here. I also added val
in the constructor of Foo2
as x
is otherwise not accessible in Bar2
.
sealed trait Foo { def x: Int }
object Bar extends Foo { val x = 5 }
sealed abstract class Foo2(val x: Int)
object Bar2 extends Foo2(5)
object Main {
def main(args: Array[String]) : Unit = {
println( Bar.x )
println( Bar2.x )
}
}
Are the two following declarations equal?
We need to define, what equal means:
- Equal wrt. general structure: No. A trait is not an abstract class. A trait can have no constructor parameters, while a class can. On the other hand, a class or object (here
Bar2
) can only derive from one (abstract) class, while it could mix-in multiple traits. A good comprehesion on traits vs. abstract class is given here: http://www.artima.com/pins1ed/traits.html#12.7 if you need to decide on a trait or a class.
- Equal wrt. byte code: No. Just run
javap -v <classfile>
to convince yourself
- Equal wrt.
Bar
and Bar2
only: Yes. Both can be accessed and used identically. Both are singletons and they expose a member variable x
that is readable (but not writable) from outside.
Also the output of scalac -print
is quite helpful, to see what is going on:
sealed abstract trait Foo extends Object {
def x(): Int
};
object Bar extends Object with com.Foo {
private[this] val x: Int = _;
<stable> <accessor> def x(): Int = Bar.this.x;
def <init>(): com.Bar.type = {
Bar.super.<init>();
Bar.this.x = 5;
()
}
};
sealed abstract class Foo2 extends Object {
<paramaccessor> private[this] val x: Int = _;
<stable> <accessor> <paramaccessor> def x(): Int = Foo2.this.x;
def <init>(x: Int): com.Foo2 = {
Foo2.this.x = x;
Foo2.super.<init>();
()
}
};
object Bar2 extends com.Foo2 {
def <init>(): com.Bar2.type = {
Bar2.super.<init>(5);
()
}
};
object Main extends Object {
def main(args: Array[String]): Unit = {
scala.this.Predef.println(scala.Int.box(Bar.x()));
scala.this.Predef.println(scala.Int.box(Bar2.x()))
};
def <init>(): com.Main.type = {
Main.super.<init>();
()
}
}