I'm trying to copy()
a Scala case class which has a type param. At the call site, the type of the value is Foo[_]
.
This compiles as expected:
case class Foo[A](id: String, name: String, v1: Bar[A])
case class Bar[A](v: A)
val foo: Foo[_] = Foo[Int]("foo1", "Foo 1", Bar[Int](1))
foo.copy(id = "foo1.1")
But if I add another member of type Bar[A]
, it doesn't compile anymore:
case class Foo[A](id: String, name: String, v1: Bar[A], v2: Bar[A])
case class Bar[A](v: A)
val foo: Foo[_] = Foo[Int]("foo1", "Foo 1", Bar[Int](1), Bar[Int](2))
foo.copy(id = "foo1.1") // compile error, see below
type mismatch;
found : Playground.Bar[_$1]
required: Playground.Bar[Any]
Note: _$1 <: Any, but class Bar is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
Error occurred in an application involving default arguments
So far I found two workarounds:
- Make
Bar
covariant inA
, then the problem hides itself because nowBar[_$1] <: Bar[Any]
- Define a
copyId(newId: String) = copy(id = newId)
method onFoo
and call that instead, then we aren't callingcopy
on a value of typeFoo[_]
.
However, neither of those are really feasible for my use case, Bar
should be invariant, and I have too many different copy
calls on Foo[_]
instances to make copyThisAndThat
methods for them all.
I guess my real question is, why is Scala behaving this way? Seems like a bug tbh.
id
orname
. I usually don't have any information available to me about the type param in such cases, thus the existential type at call site. But I do need the type param in other contexts when actually working withv1
andv2
members. – HeberFoo[_]
) those are tricky and will be reworked in Scala 3. One entity can be composed of may entities, it is really not that different for saying your case class has n fields. Also, you mentioned that you have a long code path were you do not care about the other fields, that is a good indication that you actually have more entities than one. Anyways, I just proposed a simple workaround, if you prefer to do a strange pattern match everywhere go ahead :) – Glycogenesis