95

Possible Duplicate:
Scala traits vs abstract classes

What is the conceptual difference between abstract classes and traits?

Community
  • 1
  • 1
Red Hyena
  • 2,988
  • 5
  • 25
  • 24
  • 1
    Did you see http://stackoverflow.com/questions/1991042/scala-traits-vs-abstract-classes ? There are some elements of response in that SO question. – VonC Jan 05 '10 at 11:54

4 Answers4

73

A class can only extend one superclass, and thus, only one abstract class. If you want to compose several classes the Scala way is to use mixin class composition: you combine an (optional) superclass, your own member definitions and one or more traits. A trait is restricted in comparison to classes in that it cannot have constructor parameters (compare the scala reference manual).

The restrictions of traits in comparison to classes are introduced to avoid typical problems with multiple inheritance. There are more or less complicated rules with respect to the inheritance hierarchy; it might be best to avoid a hierarchy where this actually matters. ;-) As far as I understand, it can only matter if you inherit two methods with the same signature / two variables with the same name from two different traits.

Dr. Hans-Peter Störr
  • 25,298
  • 30
  • 102
  • 139
  • You don't run into complicated scenarios as long as your hierarchy is a tree. – Raphael Jan 28 '11 at 15:56
  • @edit: You can have conflicts without the supertypes inheriting the same trait. Any two methods with same name and parameter (type) list conflict. – Raphael Feb 08 '11 at 12:36
  • @Raphael Good point. I tried to clarify this. Is it now correct? – Dr. Hans-Peter Störr Feb 11 '11 at 08:38
  • I think so. It might be noteworthy that Scala resolves such conflicts in a well defined way (the "later" trait has preference). Right now, I do not see why the same technique can not resolve class multiple inheritance, so I do not know wether the restrictions of traits are really due to that. – Raphael Feb 11 '11 at 10:32
  • Interesting reading. Honestly I can't see why one would use traits then, even though Odersky et al recommends them..? My reasons: 1. traits are not always 'callable' from java code. 2. And most importantly. By being able to extend from multiple traits, we can destroy code if we are not careful with our naming. – andershqst Jan 06 '12 at 15:29
  • 1
    @andershqst That you can abuse something is only a weak reason not to use something at all. If you want to call something from java code it is often a good idea to have it (e.g. the trait) implement a java interface. One advantage of a trait over an interface is that you can extend it later without breaking other code. (You have to recompile it, though.) I have also seen nice uses of traits where you can use variations of a basic algorithm by just including a trait. For instance in the standard library 'new TreeSet' gives you a basic set, 'new Treeset with SynchronizedSet' is synchronized. – Dr. Hans-Peter Störr Feb 02 '12 at 10:14
  • This is a difference between class-inheritance and trait-inheritance. It doesn't change if the inherited class is abstract or concrete – Paul McKenzie Sep 15 '15 at 15:18
55

One aspect of traits is that they are a stackable. Allowing a constrainted form of AOP (around advice).

trait A{
    def a = 1
}

trait X extends A{
    override def a = {
        println("X")
        super.a
    }
}  


trait Y extends A{
    override def a = {
        println("Y")
        super.a
    }
}

scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1@6e9b6a
scala> xy.a
Y
X
res0: Int = 1

scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1@188c838
scala> yx.a
X
Y
res1: Int = 1

The resolution of super reflects the linearization of the inheritance hierarchy.

Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
15

Conceptually, a trait is a component of a class, not a class by itself. As such, it typically does not have constructors, and it is not meant to "stand by itself".

I suggest using an abstract class when it has an independent meaning, and traits when you just want to add functionality in an object-oriented manner. If you're not sure between the two, you might find that if all your methods revolve around doing a single thing, you probably want a trait.

For a (non-language-specific) example, if your Employee should extend both "Person" and "Cloneable", make Person a base class and Cloneable a trait.

Oak
  • 26,231
  • 8
  • 93
  • 152
  • 1
    I would say that when all the methods revolve around doing a single thing, your design is okay (Single responsibility principle: http://en.wikipedia.org/wiki/Single_responsibility_principle). Otherwise the design should be a defendable compromise. – Thomas Jung Jan 05 '10 at 12:31
  • You're right, I clarified my answer a little. – Oak Jan 05 '10 at 13:43
5

At least in Scala, the traits system has an explicit way of declaring parent priority in a subclass to avoid typical problems associated with multiple inheritance, i.e. conflicts with inherited methods having the same signature.

Traits are akin to Java interfaces, but are allowed to have method implementations.

nbro
  • 15,395
  • 32
  • 113
  • 196
Illotus
  • 285
  • 3
  • 10
  • Binding precedence is not solved by traits per se but but by linearisation of the super type list. You could to the same thing whith multiple class inheritance. – Raphael Feb 08 '11 at 12:35