This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 8.5, “How to limit which Scala classes can use a trait by inheritance.”
Problem
You want to limit a Scala trait so it can only be added to classes that extend a superclass or another trait.
Solution
Use the following syntax to declare a trait named TraitName
, where TraitName
can only be mixed into classes that extend a type named SuperThing
, where SuperThing
may be a trait
, class
, or abstract class
:
trait [TraitName] extends [SuperThing]
For instance, in the following example, Starship
and StarfleetWarpCore
both extend the common superclass StarfleetComponent
, so the StarfleetWarpCore
trait can be mixed into the Starship
class:
class StarfleetComponent trait StarfleetWarpCore extends StarfleetComponent class Starship extends StarfleetComponent with StarfleetWarpCore
However, in the following example, the Warbird
class can’t extend the StarfleetWarpCore
trait, because Warbird
and StarfleetWarpCore
don’t share the same superclass:
class StarfleetComponent trait StarfleetWarpCore extends StarfleetComponent class RomulanStuff // won't compile class Warbird extends RomulanStuff with StarfleetWarpCore
Attempting to compile this second example yields this error:
error: illegal inheritance; superclass RomulanStuff is not a subclass of the superclass StarfleetComponent of the mixin trait StarfleetWarpCore class Warbird extends RomulanStuff with StarfleetWarpCore ^
Discussion
A trait inheriting from a class is not a common occurrence, and in general, Recipes 8.6 and Recipe 8.7 are more commonly used to limit the classes a trait can be mixed into. However, when this situation occurs, you can see how inheritance can be used. As long as a class and a trait share the same superclass — Starship
and StarfleetWarpCore
extend StarfleetComponent
— the code will compile, but if the superclasses are different (Warbird
and StarfleetWarpCore
have different superclasses), the code will not compile.
As a second example, in modeling a large pizza store chain that has a corporate office and many small retail stores, the legal department creates a rule that people who deliver pizzas to customers must be a subclass of StoreEmployee
and cannot be a subclass of CorporateEmployee
. To enforce this, begin by defining your base classes:
abstract class Employee class CorporateEmployee extends Employee class StoreEmployee extends Employee
Someone who delivers food can only be a StoreEmployee
, so you enforce this requirement in the DeliversFood
trait using inheritance like this:
trait DeliversFood extends StoreEmployee
Now you can define a DeliveryPerson
class like this:
// this is allowed class DeliveryPerson extends StoreEmployee with DeliversFood
Because the DeliversFood
trait can only be mixed into classes that extend StoreEmployee
, the following line of code won’t compile:
// won't compile class Receptionist extends CorporateEmployee with DeliversFood
Discussion
It seems rare that a trait and a class the trait will be mixed into should both have the same superclass, so I suspect the need for this recipe is also rare. When you want to limit the classes a trait can be mixed into, don’t create an artificial inheritance tree to use this recipe; use one of the following recipes instead.
See Also
- Recipe 8.6 to see how to mark Scala traits so they can only be used by subclasses of a certain type
- Recipe 8.7 to how to make sure a trait can only be mixed into a Scala class that has a specific method
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |