Question

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.

Was it helpful?

Solution

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]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top