Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"return this" in a covariant trait that return actual type

This was probably asked before, but I have this problem:

trait Container[+A] {
  def a: A

  def methodWithSideEffect() = {
    // perform some side effecting work
    this
  }
}

class IntContainer(val a: Int) extends Container[Int]

How do I have the methodWithSideEffect in IntContainer return an IntContainer instead of a Container[Int]? I would also want not to add any parameter to the Container trait, at least from the API user point of view. Note that I did make a workaround with an implicit:

implicit class MyContainer[A <: Container[_]](c: A) {
  def methodWithSideEffect(): A = {
    // perform work
    c
  }
}

However, I am quite sure there is some way to do this more elegantly.

like image 723
scand1sk Avatar asked Mar 09 '14 21:03

scand1sk


1 Answers

You can do this with a self type:

trait Container[+A] { self =>
  def a: A

  def methodWithSideEffect(): self.type = {
    // perform some side effecting work
    this
  }
}

class IntContainer(val a: Int) extends Container[Int]

...

val x: IntContainer = new IntContainer(42).methodWithSideEffect()

Or simply with this.type:

trait Container[+A] {
  def a: A

  def methodWithSideEffect(): this.type = {
    // perform some side effecting work
    this
  }
}

class IntContainer(val a: Int) extends Container[Int]
like image 67
earldouglas Avatar answered Nov 18 '22 15:11

earldouglas