Many people told me that Scala does not support multiple inheritance, but recently I read the Scala language specification, I found that Scala may already support multiple inheritance.
For example, suppose we have two classes Window and Door, now we want to define the 3rd class called WindowDoor, the most direct way in Scala is to use traits instead of classes.
The difficult part is how to deal with conflicting members.
After reading the Scala language specification, I found that Scala has a feature called static super reference, i.e. super[C].x that may deal with this situation.
See following code:
trait Window {
private[this] var _state: Boolean = false
def state: Boolean = _state
def state_=(value: Boolean): Unit = {
_state = value
}
def open() = {
println("Window open")
_state = true
}
}
trait Door {
private[this] var _state: Boolean = false
def state: Boolean = _state
def state_=(value: Boolean): Unit = {
_state = value
}
def open() = {
println("Door open")
_state = true
}
}
trait WindowDoor extends Window with Door {
override def state: Boolean = throw new Exception("WindowDoor state abandoned state")
override def state_= (x : Boolean) = throw new Exception("WindowDoor state_= abandoned state")
override def open() = {
println("WindowDoor open")
super[Door].open()
super[Window].open()
}
def stateWindow: Boolean = super[Window].state
def stateWindow_=(value: Boolean): Unit = {
super[Window].state_=(value)
}
def stateDoor: Boolean = super[Door].state
def stateDoor_=(value: Boolean): Unit = {
super[Door].state_=(value)
}
}
object WindowDoor {
def create(s1 : Boolean, s2: Boolean) : WindowDoor = {
val obj = new WindowDoor {}
obj.stateWindow = s1
obj.stateDoor = s2
obj
}
}
val windowDoor = WindowDoor.create(false, false)
windowDoor.open()
windowDoor.stateDoor
windowDoor.stateWindow
// Output:
// WindowDoor open
// Door open
// Window open
Note that
-
I use factory method to create object instead of
new, because trait cannot have any “class” parameters. -
Since I use
traitsinstead ofclasses, theWindowandDoorevenWindowDoorcan be reused in the future.
BTW this feature does not mentioned in the book Programming in Scala.
In the Chapter 12.6 - Why not multiple inheritance?
Authors mentioned that
For example, imagine the following Scala-like code, in which super appears to be explicitly invoked on both Incrementing and Doubling:
// Multiple inheritance thought experiment
trait MyQueue extends BasicIntQueue
with Incrementing with Doubling {
def put(x: Int) = {
Incrementing.super.put(x) // (Not real Scala)
Doubling.super.put(x)
}
}
According to the authors, the above code is just pseudo-code, it does not really exist in the Scala language.
But in fact, Scala supports this kind of explicitly invoking super-trait, right? (or Scala’s designers discourage the use of static super reference?)
super[Incrementing].put(x)
super[Doubling].put(x)
Another way to implement WindowDoor is to separate State “classes” and Behavior “classes”.
See following code:
trait IOpen {
def open()
}
trait IOpenDefaultImpl extends IOpen {
override def open() = {
println("IOpenDefaultImpl open")
}
}
trait WindowState {
private[this] var _state: Boolean = false
def state: Boolean = _state
def state_=(value: Boolean): Unit = {
_state = value
}
}
trait WindowBehavior extends WindowState with IOpen {
abstract override def open() = {
println("WindowBehavior open")
super.open()
super[WindowState].state_=(true)
}
}
trait DoorState {
private[this] var _state: Boolean = false
def state: Boolean = _state
def state_=(value: Boolean): Unit = {
_state = value
}
}
trait DoorBehavior extends DoorState with IOpen {
abstract override def open() = {
println("DoorBehavior open")
super.open()
super[DoorState].state_=(true)
}
}
trait WindowDoorState extends WindowState with DoorState {
override def state: Boolean = throw new Exception("WindowDoorState state abandoned state")
override def state_= (x : Boolean) = throw new Exception("WindowDoorState state_= abandoned state")
def stateWindow: Boolean = super[WindowState].state
def stateWindow_=(value: Boolean): Unit = {
super[WindowState].state_=(value)
}
def stateDoor: Boolean = super[DoorState].state
def stateDoor_=(value: Boolean): Unit = {
super[DoorState].state_=(value)
}
}
trait Window extends WindowState
with IOpenDefaultImpl
with WindowBehavior
object Window {
def create(s : Boolean) : Window = {
val obj = new Window {}
obj.state = s
obj
}
}
trait Door extends DoorState
with IOpenDefaultImpl
with DoorBehavior
object Door {
def create(s : Boolean) : Door = {
val obj = new Door {}
obj.state = s
obj
}
}
trait WindowDoor extends WindowDoorState
with IOpenDefaultImpl
with WindowBehavior
with DoorBehavior
object WindowDoor {
def create(s1 : Boolean, s2: Boolean) : WindowDoor = {
val obj = new WindowDoor {}
obj.stateWindow = s1
obj.stateDoor = s2
obj
}
}
trait DoorWindow extends WindowDoorState
with IOpenDefaultImpl
with DoorBehavior
with WindowBehavior
object DoorWindow {
def create(s1 : Boolean, s2: Boolean) : DoorWindow = {
val obj = new DoorWindow {}
obj.stateWindow = s1
obj.stateDoor = s2
obj
}
}
println("----test window----")
val window = Window.create(false)
window.open()
window.state
println("----test door----")
val door = Door.create(false)
door.open()
door.state
println("----test windowDoor----")
val windowDoor = WindowDoor.create(false, false)
windowDoor.open()
windowDoor.stateDoor
windowDoor.stateWindow
println("----test doorWindow----")
val doorWindow = DoorWindow.create(false, false)
doorWindow.open()
doorWindow.stateDoor
doorWindow.stateWindow
// Output
----test window----
WindowBehavior open
IOpenDefaultImpl open
----test door----
DoorBehavior open
IOpenDefaultImpl open
----test windowDoor----
DoorBehavior open
WindowBehavior open
IOpenDefaultImpl open
----test doorWindow----
WindowBehavior open
DoorBehavior open
IOpenDefaultImpl open
The code above did two things:
-
Merge two State Traits to one State Trait and rename conflicting members by
static super reference. -
Do stackable modifications on Behavior Traits by
overrideandsuper.
Therefore, can I think of Scala already support multiple-inheritance?
If not, which multiple-inheritance features are still lacking in Scala?
Thanks.
PS: I’m sorry I know there is already a post about multiple-inheritance, but the system prompts me that the last reply to that thread was 8 months ago. It seems tends to let me create a new one.