Vangogh500
Vangogh500

Reputation: 959

Any ways to have generic case classes or have a trait that specifies a copy method with a specific param?

Hi so I have this use case where I have a function which takes a type which extends a trait. Let's say the trait a is:

trait A {
   val a: Double
}

Now I have multiple case classes that extend a.

case class B(val a: Double) extends A 
case class C(val a: Double, val b: Double) extends A

Now I want a generalized funtion such as:

def change[T <: A](newA: Double, state: T): T = {
   state.copy(a = newA)
}

If I can some how specify that the generic T is a case class that extends A, I can than infer that state has a clone method that has a param a. Or maybe there is a way to define a generic that says that there is a clone function that has exactly one param that is a.

Thanks

Upvotes: 2

Views: 376

Answers (1)

Suma
Suma

Reputation: 34463

Building on a comment by cchantep, and on a similar question I have asked recently, following works:

trait A[T <: A[T]] {
  val a: Double
  def clone(a: Double = a): T
}

case class B(a: Double) extends A[B] {
  def clone(a: Double = a) = copy(a = a)
}

case class C(a: Double, b: Double) extends A[C] {
  def clone(a: Double = a) = copy(a = a)
}

def change[T <: A[T]](newA: Double, state: T): T = {
  state.clone(a = newA)
}

Is there any reason why do you want change to return the specific type and not just A? Without this requirement is could be a lot simpler, I have added the recursive type only to meet this requirement (to describe clone is always returning the original type):

trait A {
  val a: Double

  def clone(a: Double = a): A
}

case class B(a: Double) extends A {
  def clone(a: Double = a) = copy(a = a)
}

case class C(a: Double, b: Double) extends A {
  def clone(a: Double = a) = copy(a = a)
}

def change(newA: Double, state: A): A = {
  state.clone(a = newA)
}

Even with this simple implementation you could use clone directly instead of change and it would still keep the derived type statically. Still, I think such requirement makes little sense, and in the situations you compiler knows it is B or C, not A, you can use copy directly, you need change only when you have A only.

Upvotes: 1

Related Questions