I've seen some blogs on the Pimp my Library pattern
, and these seem to work well for adding behavior to classes.
But what if I have a case class
and I want to add data members
to it? As a case class I can't extend it (inheriting from a case class is deprecated/strongly discouraged). Will any of these pimp patterns allow me to add data to a case class?
No - I don't see how you could make this work because the enriched instance is usually thrown away (note: newly the pimp-my-library pattern is called enrich-my-library). For example:
scala> case class X(i: Int, s: String)
defined class X
scala> implicit class Y(x: X) {
| var f: Float = 0F
| }
defined class Y
scala> X(1, "a")
res17: X = X(1,a)
scala> res17.f = 5F
res17.f: Float = 0.0
scala> res17.f
res18: Float = 0.0
You would have to make sure you kept hold of the wrapped instance:
scala> res17: Y
res19: Y = Y@4c2d27de
scala> res19.f = 4
res19.f: Float = 4.0
scala> res19.f
res20: Float = 4.0
However, I find this not useful in practice. You have a wrapper; you're better off making this explicit
This is not the way to do. Just a proof of possibility. With this way you can get plenty of problems.
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class A(i: Int)
class B(a: A){
var s: String = ""
}
object B{
val as = scala.collection.mutable.WeakHashMap[A, B]()
}
implicit def a2b(a: A) = B.as.getOrElseUpdate(a, new B(a))
// Exiting paste mode, now interpreting.
defined class A
defined class B
defined module B
a2b: (a: A)B
scala> val a = A(1)
a: A = A(1)
scala> a.s = "test"
scala> a.s
res0: String = test
WeakHashMap: A hash map with references to entries which are weakly reachable. Entries are removed from this map when the key is no longer (strongly) referenced. This class wraps java.util.WeakHashMap.
Note that due to case class
's overridden equals
method you get this funny behavior:
scala> A(2).s = "test2"
scala> A(2).s
res2: String = test2
so you should not use case class
or use it with override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
.