{{announcement.body}}
{{announcement.title}}

The Practical Difference Between Abstract Classes and Traits in Scala

DZone 's Guide to

The Practical Difference Between Abstract Classes and Traits in Scala

This short article will compare abstract classes and traits as means of inheritance.

· Java Zone ·
Free Resource

This short article will compare abstract classes and traits as means of inheritance. This is for the beginner Scala programmer who is just getting started with Scala's inheritance model. If you're trying to figure out which is the best way to create OO-style type hierarchies and abstract classes seem too similar to traits, this article is for you.

You can read this article over at Rock the JVM or watch it on YouTube or in the video below:


Background

Scala is particularly permissive when it comes to inheritance options. Of course, Scala has a single-class inheritance model, where one can extend a single class. Much like Java, Scala classes can inherit from multiple traits (the equivalent of Java interfaces).

Scala also has the concept of an abstract class, where one can

  • restrict the ability of a class to be instantiated
  • add unimplemented fields or methods
Scala
 




x


 
1
abstract class Person {
2
  // the abstract keyword is not necessary in the field/method definition
3
  val canDrive: Boolean
4
  def discussWith(another: Person): String
5
}
6
 
          
7
val bob = new Person // error - not all members implemented



An abstract class may or may not have either abstract (unimplemented) or non-abstract (implemented) methods.

However, traits also share most of the same capabilities:

  • they can't be instantiated by themselves
  • they may have abstract (unimplemented) fields or methods
  • (more importantly) they may have non-abstract (implemented) fields and methods as well

So while teaching Scala at Rock the JVM, I often come across this popular question: how are traits and abstract classes really different?

The Similarity

There is little practical difference between an abstract class and a trait if you extend a single one. If you look at the example below:

Scala
 




xxxxxxxxxx
1


 
1
class Adult(val name: String, hasDrivingLicence: Boolean) extends Person {
2
  override def toString: String = name
3
  override val canDrive: Boolean = hasDrivingLicence
4
  override def discussWith(another: Person): String = "Indeed, ${other}, Kant was indeed revolutionary for his time..."
5
}



The code is identical, regardless of whether Person was a trait or an abstract class. So from this point of view, a trait and an abstract class are identical.

The Practical Differences

When we move towards multiple inheritance, things start to look different. One of the fundamental differences between a trait and an abstract class is that multiple traits may be used in the inheritance definition of a class, whereas a single abstract class can be extended. Since traits can have non-abstract methods as well, a good (and natural) follow-up question might be: "but what happens if a class inherits from two traits with the same method implemented in different ways?", which resembles the famous diamond problem. Scala solves it with a dedicated mechanism called linearization, which we will discuss in another article.

A second, more practical difference between a trait and an abstract class is that an abstract class can take constructor arguments:

Scala
 




xxxxxxxxxx
1


 
1
abstract class Person(name: String, age: Int)



whereas traits cannot:

Scala
 




xxxxxxxxxx
1


 
1
trait Person(name: String, age: Int) // error



That is, at least until Scala 3 comes out - Scala 3 will also allow constructor arguments for traits.

The Subtle Difference

When I speak in a live training at Rock the JVM about the above differences between traits and abstract classes, my audience is usually not impressed - it seems the overlap is so large that there might be no purpose to two different concepts.

However, I always end up with the following reasoning: for good practice, it is always a good idea to make code easy to read, understand and reason about. To this aim, we generally represent "things" as classes, and "behaviors" as traits. This conceptual difference is directly mapped in the language: a "thing" (class) can be a specialized version of another "thing" (also a class), but might incorporate multiple "behaviors" (traits).

Conclusion

Abstract classes and traits are distinct concepts with a lot of mechanical overlap. You now understand how they're (very) similar and how they are different - both in terms of Scala mechanics and in terms of how we read and understand code.

I hope this was useful! Check out the Rock the JVM channel and follow us on Twitter and LinkedIn for updates on upcoming material and stay tuned either here on DZone or on the blog!
Topics:
abstract classes, java, object-oriented programming, scala, tutorial

Published at DZone with permission of Daniel Ciocirlan . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}