3

To simplify my actual code let's say there are two classes, one a subclass of the other:

class Chair {
   val canFold = false;
   // ...
}

class FoldableChair extends Chair {
   val canFold = true;
   // ...
} 

and in my implementation I will have potentially hundreds of other subclasses of Chair or FoldableChair:

class Armchair extends ... {}
class DeckChair extends ... {} 
//... etc

For each of these subclasses, suppose each one has a lengthy implementation but I want to be able to have it sometimes extend Chair and sometimes extend FoldableChair - without duplicating the code. I'd like to do so without having the subclass itself be extended. Is this possible somehow? Do I need to use traits to do this?

I'd also like to be able to create particular instances of a subclass which sometimes extend Chair and sometimes extend FoldableChair, but that choice is made when instantiating it. Is this possible too? Thanks!

Edit: to clarify, what I really want is this:

class Armchair extends Chair {}

class ArmchairFoldable extends FoldableChair {}

but the implementation of Armchair and ArmchairFoldable are exactly the same. That is, I'd like to not duplicate their implementations.

Heinrich Schmetterling
  • 6,614
  • 11
  • 40
  • 56

1 Answers1

5

You can use an implementation trait; i.e., a trait that you mix in with a class and that provides additional members with their implementation.

Example:

class Chair {
   // you can use a def rather than a val as it's constant and
   // and doesn't need to occupy a field
   def canFold = false

   // ...
}

class FoldableChair extends Chair {
   override def canFold = true
   // ...
}

trait Extensible extends Chair {
    // this trait extends Chair to mean that it is only
    // applicable to Chair or subclasses of Chair
    def extend = /* ... */
}

class FoldableExtensibleChair extends FoldableChair with Extensible

Then you can write:

val a = new Chair // bare-bones chair

// decide at creation time that this one is extensible
val b = new Chair with Extensible

val c = new FoldableChair // non extensible

// use predefined class which already mixes in Extensible
val d = new FoldableExtensibleChair 
Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • Rather than `trait Extensible extends Chair` to enforce that `Extensible` only applies to `Chair`, isn't it customary to use a self-type? `trait Extensible { self: Chair => ... }` Not 100% sure of the trade-offs. Just asking. – overthink Apr 29 '11 at 15:15
  • @overthink Yes, it is customary to use self types in this kind of situation. – Daniel C. Sobral Apr 29 '11 at 19:47
  • The `extends Chair` style is used in Bill Venners's article linked by Frank Thomas and also appears more prominently in the Programming in Scala book. See that question, for which Daniel provided a very nice answer: http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclasses – Jean-Philippe Pellet Apr 29 '11 at 21:29
  • philippe this doesn't do quite what i want because in my case i want to have a 3rd subclass (Armchair in the edited question) that sometimes inherits from Chair and sometimes from FoldableChair. but i don't want to duplicate the two implementations. and also i want Armchair to subclass from Chair and but particular instances of Armchair can also subclass from FoldableChair. – Heinrich Schmetterling Apr 30 '11 at 01:16