Nathaniel Ford
Nathaniel Ford

Reputation: 21220

Idiomatic Way To Merge Trait Functionality

Suppose I have the following:

abstract class Service {}
case class Blue() extends Service
case class Green() extends Service
case class Red() extends Service

abstract trait Material {
  def supports(s: Service): Service
}

trait Wood extends Material {
  def supports(s: Service): Boolean = {
    s match {
      case _:Blue => false
      case _:Green => true
      case _ => false
    }
  }
}

trait Stone extends Material {
  def supports(s: Service): Boolean = {
    s match {
      case _:Blue => true
      case _:Green => false
      case _ => false
    }
  }
}

Now, what I want to do is have a type MyService that is both Stone and Wood, such that MyService.supports(service) will return true if service is either Blue or Green, but false if it is Red:

case class MyService() extends Wood with Stone
service = new MyService()
service.supports(new Blue()) //true
service.supports(new Green()) //true
service.supports(new Red()) //false

Obviously the above creates a conflict because both Wood and Stone implement the same method. I could create a new trait StoneAndWood, but that seems inelegant. Is there an elegant way of merging those two functions (essentially putting a boolean or between them?). Would a different class design make this task easier?

Upvotes: 3

Views: 196

Answers (2)

Pillsy
Pillsy

Reputation: 9901

How about having each subclass of Material call its superclass's supports method if it doesn't support the service? Something like this:

abstract trait Material {
  def supports (s: Service) = false
}

trait Wood extends Material {
  override def supports (s: Service) = 
   s match { 
    case _: Green => True; 
    case _       => super supports s
 }
}

trait Stone extends Material {
  override def supports (s: Service) = 
   s match { 
     case _: Blue => True; 
     case _       => super supports s
 }
}

Upvotes: 1

Gustek
Gustek

Reputation: 3760

You can do something like this

class WoodStone extends Wood with Stone {
  override def supports(s: Service): Boolean = {
    super[Wood].supports(s) || super[Stone].supports(s)
  }
}

Upvotes: 0

Related Questions