This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 4.12, “When to use an abstract class in Scala.”
Problem
Scala has traits, and a trait is more flexible than an abstract class, so you wonder, “When should I use an abstract class?”
Solution
There are two main reasons to use an abstract class in Scala:
- You want to create a base class that requires constructor arguments.
- The code will be called from Java code.
Regarding the first reason, traits don’t allow constructor parameters:
// this won't compile trait Animal(name: String)
So, use an abstract class whenever a base behavior must have constructor parameters:
abstract class Animal(name: String)
Regarding the second reason, if you’re writing code that needs to be accessed from Java, you’ll find that Scala traits with implemented methods can’t be called from Java code. If you run into this situation, see Recipe 17.7, “Wrapping Traits with Implementations”, for solutions to that problem.
Discussion
Use an abstract class instead of a trait when the base functionality must take constructor parameters. However, be aware that a class can extend only one abstract class.
Abstract classes work just like Java in that you can define some methods that have complete implementations, and other methods that have no implementation and are therefore abstract. To declare that a method is abstract
, just leave the body of the method undefined:
def speak // no body makes the method abstract
There is no need for an abstract
keyword; simply leaving the body of the method undefined makes it abstract. This is consistent with how abstract methods in traits are defined.
In the following example the methods save
, update
, and delete
are defined in the abstract class BaseController
, but the methods connect
, getStatus
, and setServerName
have no method body, and are therefore abstract:
abstract class BaseController(db: Database) { def save { db.save } def update { db.update } def delete { db.delete } // abstract def connect // an abstract method that returns a String def getStatus: String // an abstract method that takes a parameter def setServerName(serverName: String) }
When a class extends the BaseController
class, it must implement the connect
, getStatus
, and setServerName
methods, or be declared abstract
. Attempting to extend BaseController
without implementing those methods yields a “class needs to be abstract” error, as shown in the REPL:
scala> class WidgetController(db: Database) extends BaseController(db) <console>:9: error: class WidgetController needs to be abstract, since: method setServerName in class BaseController of type (serverName: String)Unit is not defined method getStatus in class BaseController of type => String is not defined method connect in class BaseController of type => Unit is not defined class WidgetController(db: Database) extends BaseController(db) ^
Because a class can extend only one abstract class, when you’re trying to decide whether to use a trait or abstract class, always use a trait, unless you have this specific need to have constructor arguments in your base implementation.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |