Question

situation:

trait Operation {
def something: Double 
}

trait OperationPlus { this: A =>
override def something: Double = x + y
}
trait OperationMinus { this: A =>
    override def something: Double = x - y
}

case class A(x: Double, y: Double) { this:  Operation =>
}

val a = new A(1.0, 2.0) with OperationPlus
  println(a.something)

error:

class A cannot be instantiated because it does not conform to its self-type A with Operation

Also, i can't instantiate A.

I tried multiple different approaches, but none provided what i'm looking for. I don't want to use case class inheritance, or give up case classes, and ideally trait / self types / something else should do the trick. Any ideas?

Update preferred solution

 trait Operation { this: A =>
 def something: Double 
 }

 trait OperationPlus extends Operation { this: A =>
   override def something: Double = x + y
 }
 trait OperationMinus extends Operation { this: A =>
     override def something: Double = x - y
 }

 abstract case class A(val x: Double, val y: Double) extends Operation

 val a = new A(1.0, 2.0) with OperationPlus
 println(a.something)

 val b = new A(1.0, 2.0) with OperationMinus
 println(b.something)

possible solution 1:

trait Operation {
  def x:Double 
  def y:Double
  def something: Double 
}

trait OperationPlus extends Operation {
  override def something: Double = x + y
}
trait OperationMinus extends Operation {
      override def something: Double = x - y
}

abstract case class A(val x: Double, val y: Double) extends Operation 

By using conventional classes, simple trait inheritance and a self-type in the actual value is possible to define it and supply behaviour dynamically.

Unfortunately, I have to redefine the fields in the trait. I guess is a fair compromise. Would be interested to know if somebody knows of another approach.

Thanks

Was it helpful?

Solution

Not sure about your use case, but you need to define class A like this if you want to make it work:

abstract case class A(x: Double, y: Double) extends Operation

But I don't think is very idiomatic approach to use case classes. They are mostly used as data containers and normally do not contain any behavior. (maybe you can tell some more information about things you want to achieve with this)

OTHER TIPS

First, you should have:

trait OperationPlus extends Operation
trait OperationMinus extends Operation

Second, you cannot define A as case class, since that automatically defines the apply method on the companion object, where new A is called (with arguments). This call fails due to the wrong self type (the error you see).

Remove the case. If you need pattern matching, define an extractor yourself (implement unapply):

class A(val x: Double, val y: Double) { this: Operation => }

object A {
  def unapply(v: A) = Some((v.x, v.y))
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top