4

Assuming no multiple inheritance and no concerns about interoperability with Java, are the two following declarations equal?

sealed trait Foo { def x: Int }
case object Bar extends Foo { val x = 5 }

and

sealed abstract class Foo(val x: Int)
case object Bar extends Foo(5)
5
  • 2
    Possible duplicate of What is the advantage of using abstract classes instead of traits? Commented Oct 5, 2015 at 22:40
  • I've read that thread, I'm asking about this specific example from a purely behavioral point of view. Commented Oct 5, 2015 at 22:43
  • 1
    I am not a Scala expert, but I would assume they need to be equivalent in the same way that it would be equivalent comparing (for this concrete example) an abstract class and an interface in Java. Commented Oct 5, 2015 at 22:46
  • 1
    note that you need val x: Int in abstract class example, otherways it's just unused constructor parameter which results in ` error: value x is not a member of object Bar` when calling Bar.x Commented Oct 6, 2015 at 9:16
  • @Łukasz I see! Thanks for pointing this out Commented Oct 8, 2015 at 2:20

2 Answers 2

2

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>();
    ()
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

No, these are not equivalent and can lead to trouble later with initialization order. I've added exactly the same line of code to each, showing they were never equal code blocks.

sealed trait Foo {
    def x: Int
    val calc = x * 5 / 2  //at the time this runs, x is actually 0
  }
  case object Bar extends Foo {
    val x = 5

  }


  sealed abstract class Foo2(x: Int){
    val calc = x * 5 / 2
  }
  case object Bar2 extends Foo2(5)

  println(Bar.calc)
  println(Bar2.calc)

  //output  0  12 

1 Comment

Downvote, as answer is not comprehensive enough. Second, initialization order needs extreme care, but is not relevant in the case, user2066880 has given.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.