How to deep copy classes with traits mixed in - scala

Here's some sample scala code.
abstract class A(val x: Any) {
abstract def copy(): A
}
class b(i: Int) extends A(i) {
override def copy() = new B(x)
}
class C(s: String) extends A(s) {
override def copy() = new C(x)
}
//here's the tricky part
Trait t1 extends A {
var printCount = 0
def print = {
printCount = printCount + 1
println(x)
}
override def copy = ???
}
Trait t2 extends A {
var doubleCount = 0
def doubleIt = {
doubleCount = doubleCount + 1
x = x+x
}
override def copy = ???
}
val q1 = new C with T1 with T2
val q2 = new B with T2 with T1
OK, as you've likely guessed, here's the question.
How can I implement copy methods in T1 and T2, such that weather they are mixed in with B, C, or t2/t1, I get a copy of the whole ball of wax?
for example, q2.copy should return a new B with T2 with T1, and q1.copy should return a new C with T1 with T2
Thanks!

Compositionality of object construction
The basic problem here is, that, in Scala as well as in all other languages I know, object construction doesn't compose. Consider two abstract operations op1 and op2, where op1 makes property p1 true and where op2 makes property p2 true. These operations are composable with respect to a composition operation ○, if op1 ○ op2 makes both p1 and p2 true. (Simplified, properties also need a composition operation, for example conjunction such as and.)
Let's consider the new operation and the property that new A(): A, that is, an object created by calling new A is of type A. The new operation lacks compositionality, because there is no operation/statement/function f in Scala that allows you to compose new A and new B such that f(new A, new B): A with B. (Simplified, don't think too hard about whether A and B must be classes or traits or interfaces or whatever).
Composing with super-calls
Super-calls can often be used to compose operations. Consider the following example:
abstract class A { def op() {} }
class X extends A {
var x: Int = 0
override def op() { x += 1 }
}
trait T extends A {
var y: String = "y"
override def op() { super.op(); y += "y" }
}
val xt = new X with T
println(s"${xt.x}, ${xt.y}") // 0, y
xt.op()
println(s"${xt.x}, ${xt.y}") // 1, yy
Let X.op's property be "x is increased by one" and let T.op's property be "y's length is increased by one". The composition achieved with the super-call fulfils both properties. Hooooray!
Your problem
Let's assume that you are working with a class A which has a field x, a trait T1 which has a field y and another trait T2 which has a field z. What you want is the following:
val obj: A with T1 with T2
// update obj's fields
val objC: A with T1 with T2 = obj.copy()
assert(obj.x == objC.x && obj.y == objC.y && obj.z == objC.z)
Your problem can be divided into two compositionality-related sub-problems:
Create a new instance of the desired type. This should be achieved by a construct method.
Initialise the newly created object such that all its fields have the same values (for brevity, we'll only work with value-typed fields, not reference-typed ones) as the source object. This should be achieved by a initialise method.
The second problem can be solved via super-calls, the first cannot. We'll consider the easier problem (the second) first.
Object initialisation
Let's assume that the construct method works as desired and yields an object of the right type. Analogous to the composition of the op method in the initial example we could implement initialise such that each class/trait A, T1 and T2 implements initialise(objC) by setting the fields it knows about to the corresponding values from this (individual effects), and by calling super.initialise(objC) in order to compose these individual effects.
Object creation
As far as I can see, there is no way to compose object creation. If an instance of A with T1 with T2 is to be created, then the statement new A with T1 with T2 must be executed somewhere. If super-calls could help here, then something like
val a: A = new A // corresponds to the "deepest" super-call
val at1: A with T1 = a with new T1
would be necessary.
Possible solutions
I implemented a solution (see this gist) based on abstract type members and explicit mixin classes (class AWithT1WithT2 extends A with T1 with T2; val a = new AWithT1WithT2 instead of val a = new A with T1 with T2). It works and it is type-safe, but it is neither particularly nice nor concise. The explicit mixin classes are necessary, because the construct method of new A with T1 with T2 must be able to name the type it creates.
Other, less type-safe solutions are probably possible, for example, casting via asInstanceOf or reflection. I haven't tried something along those lines, though.
Scala macros might also be an option, but I haven't used them yet and thus don't know enough about them. A compiler plugin might be another heavy-weight option.

That is one of the reasons, why extending case classes is deprecated. You should get a compiler warning for that. How should the copy method, that is defined in A, know, that there may also be a T or whatever? By extending the case class,
you break all the assumptions, that the compiler made, when generating methods like equals, copy and toString.

The easiest and simplest answer is to make your concrete types into case classes. Then you get the compiler-supplied copy method which accepts named parameters for all the class's constructor parameters so you can selectively differentiate the new value from the original.

Related

How does Scala transform case classes to be accepted as functions?

I am trying to understand how a case class can be passed as an argument to a function which accepts functions as arguments. Below is an example:
Consider the below function
def !![B](h: Out[B] => A): In[B] = { ... }
If I understood correctly, this is a polymorphic method which has a type parameter B and accepts a function h as a parameter. Out and In are other two classes defined previously.
This function is then being used as shown below:
case class Q(p: boolean)(val cont: Out[R])
case class R(p: Int)
def g(c: Out[Q]) = {
val rin = c !! Q(true)_
...
}
I am aware that currying is being used to avoid writing the type annotation and instead just writing _. However, I cannot grasp why and how the case class Q is transformed to a function (h) of type Out[B] => A.
EDIT 1 Updated !! above and the In and Out definitions:
abstract class In[+A] {
def future: Future[A]
def receive(implicit d: Duration): A = {
Await.result[A](future, d)
}
def ?[B](f: A => B)(implicit d: Duration): B = {
f(receive)
}
}
abstract class Out[-A]{
def promise[B <: A]: Promise[B]
def send(msg: A): Unit = promise.success(msg)
def !(msg: A) = send(msg)
def create[B](): (In[B], Out[B])
}
These code samples are taken from the following paper: http://drops.dagstuhl.de/opus/volltexte/2016/6115/
TLDR;
Using a case class with multiple parameter lists and partially applying it will yield a partially applied apply call + eta expansion will transform the method into a function value:
val res: Out[Q] => Q = Q.apply(true) _
Longer explanation
To understand the way this works in Scala, we have to understand some fundamentals behind case classes and the difference between methods and functions.
Case classes in Scala are a compact way of representing data. When you define a case class, you get a bunch of convenience methods which are created for you by the compiler, such as hashCode and equals.
In addition, the compiler also generates a method called apply, which allows you to create a case class instance without using the new keyword:
case class X(a: Int)
val x = X(1)
The compiler will expand this call to
val x = X.apply(1)
The same thing will happen with your case class, only that your case class has multiple argument lists:
case class Q(p: boolean)(val cont: Out[R])
val q: Q = Q(true)(new Out[Int] { })
Will get translated to
val q: Q = Q.apply(true)(new Out[Int] { })
On top of that, Scala has a way to transform methods, which are a non value type, into a function type which has the type of FunctionX, X being the arity of the function. In order to transform a method into a function value, we use a trick called eta expansion where we call a method with an underscore.
def foo(i: Int): Int = i
val f: Int => Int = foo _
This will transform the method foo into a function value of type Function1[Int, Int].
Now that we posses this knowledge, let's go back to your example:
val rin = c !! Q(true) _
If we just isolate Q here, this call gets translated into:
val rin = Q.apply(true) _
Since the apply method is curried with multiple argument lists, we'll get back a function that given a Out[Q], will create a Q:
val rin: Out[R] => Q = Q.apply(true) _
I cannot grasp why and how the case class Q is transformed to a function (h) of type Out[B] => A.
It isn't. In fact, the case class Q has absolutely nothing to do with this! This is all about the object Q, which is the companion module to the case class Q.
Every case class has an automatically generated companion module, which contains (among others) an apply method whose signature matches the primary constructor of the companion class, and which constructs an instance of the companion class.
I.e. when you write
case class Foo(bar: Baz)(quux: Corge)
You not only get the automatically defined case class convenience methods such as accessors for all the elements, toString, hashCode, copy, and equals, but you also get an automatically defined companion module that serves both as an extractor for pattern matching and as a factory for object construction:
object Foo {
def apply(bar: Baz)(quux: Corge) = new Foo(bar)(quux)
def unapply(that: Foo): Option[Baz] = ???
}
In Scala, apply is a method that allows you to create "function-like" objects: if foo is an object (and not a method), then foo(bar, baz) is translated to foo.apply(bar, baz).
The last piece of the puzzle is η-expansion, which lifts a method (which is not an object) into a function (which is an object and can thus be passed as an argument, stored in a variable, etc.) There are two forms of η-expansion: explicit η-expansion using the _ operator:
val printFunction = println _
And implicit η-expansion: in cases where Scala knows 100% that you mean a function but you give it the name of a method, Scala will perform η-expansion for you:
Seq(1, 2, 3) foreach println
And you already know about currying.
So, if we put it all together:
Q(true)_
First, we know that Q here cannot possibly be the class Q. How do we know that? Because Q here is used as a value, but classes are types, and like most programming languages, Scala has a strict separation between types and values. Therefore, Q must be a value. In particular, since we know class Q is a case class, object Q is the companion module for class Q.
Secondly, we know that for a value Q
Q(true)
is syntactic sugar for
Q.apply(true)
Thirdly, we know that for case classes, the companion module has an automatically generated apply method that matches the primary constructor, so we know that Q.apply has two parameter lists.
So, lastly, we have
Q.apply(true) _
which passes the first argument list to Q.apply and then lifts Q.apply into a function which accepts the second argument list.
Note that case classes with multiple parameter lists are unusual, since only the parameters in the first parameter list are considered elements of the case class, and only elements benefit from the "case class magic", i.e. only elements get accessors implemented automatically, only elements are used in the signature of the copy method, only elements are used in the automatically generated equals, hashCode, and toString() methods, and so on.

How to change a base class attribute of a case class

Take the following code:
class A(val i: Int)
case class B(str: String) extends A(1)
val b = B("test")
In my scenario I am restricted by the definition of B which cannot be changed. I also wish to avoid reconstructing B as I have many such objects with a lot more attributes than in this example.
Is there any way I can create a new copy of b (using reflection or otherwise) with a new value for i?
Something that would be the equivalent of:
val b2 = b.copy(i = 2)
NOTE: The question is can it be done? Not what the best programming practice is.
You can do it using reflection with something like this:
val b = B("foo")
val c = b.copy()
println(b.i) // prints 1
val field = classOf[A].getDeclaredFields.head
field.setAccessible(true)
field.setInt(c, 2)
println(c.i) // prints 2
But beware, this is not just "bad programming practice", but rather complete breakage of the contract.
Your declaration case class B(s: Sting) extends A(1) promises that all instances of B will always have i equal to 1, which is a lie.
Not to mention, fun facts like b == c being true or c.copy.i being 1 etc.
Don't do this.
Not if you define B that way. But this code works for me:
class A(val i: Int)
case class B(str: String, override val i:Int=1) extends A(i)
val b = B("test")
val b2 = b.copy(i = 2)
P.S. well technically you can just copy with no modifications and then edit i using reflection but this is not a great idea IMHO.
You can do this:
val b2 = new B(b.str) { override val i = 2 }
The downside is that you have to re-construct B from the parameters which may be cumbersome if there are a lot of them.

Why do each new instance of case classes evaluate lazy vals again in Scala?

From what I have understood, scala treats val definitions as values.
So, any instance of a case class with same parameters should be equal.
But,
case class A(a: Int) {
lazy val k = {
println("k")
1
}
val a1 = A(5)
println(a1.k)
Output:
k
res1: Int = 1
println(a1.k)
Output:
res2: Int = 1
val a2 = A(5)
println(a1.k)
Output:
k
res3: Int = 1
I was expecting that for println(a2.k), it should not print k.
Since this is not the required behavior, how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once. Do I need some memoization technique or Scala can handle this on its own?
I am very new to Scala and functional programming so please excuse me if you find the question trivial.
Assuming you're not overriding equals or doing something ill-advised like making the constructor args vars, it is the case that two case class instantiations with same constructor arguments will be equal. However, this does not mean that two case class instantiations with same constructor arguments will point to the same object in memory:
case class A(a: Int)
A(5) == A(5) // true, same as `A(5).equals(A(5))`
A(5) eq A(5) // false
If you want the constructor to always return the same object in memory, then you'll need to handle this yourself. Maybe use some sort of factory:
case class A private (a: Int) {
lazy val k = {
println("k")
1
}
}
object A {
private[this] val cache = collection.mutable.Map[Int, A]()
def build(a: Int) = {
cache.getOrElseUpdate(a, A(a))
}
}
val x = A.build(5)
x.k // prints k
val y = A.build(5)
y.k // doesn't print anything
x == y // true
x eq y // true
If, instead, you don't care about the constructor returning the same object, but you just care about the re-evaluation of k, you can just cache that part:
case class A(a: Int) {
lazy val k = A.kCache.getOrElseUpdate(a, {
println("k")
1
})
}
object A {
private[A] val kCache = collection.mutable.Map[Int, Int]()
}
A(5).k // prints k
A(5).k // doesn't print anything
The trivial answer is "this is what the language does according to the spec". That's the correct, but not very satisfying answer. It's more interesting why it does this.
It might be clearer that it has to do this with a different example:
case class A[B](b: B) {
lazy val k = {
println(b)
1
}
}
When you're constructing two A's, you can't know whether they are equal, because you haven't defined what it means for them to be equal (or what it means for B's to be equal). And you can't statically intitialize k either, as it depends on the passed in B.
If this has to print twice, it would be entirely intuitive if that would only be the case if k depends on b, but not if it doesn't depend on b.
When you ask
how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once
that's a trickier question than it sounds. You make "the same parameters" sound like something that can be known at compile time without further information. It's not, you can only know it at runtime.
And if you only know that at runtime, that means you have to keep all past uses of the instance A[B] alive. This is a built in memory leak - no wonder Scala has no built-in way to do this.
If you really want this - and think long and hard about the memory leak - construct a Map[B, A[B]], and try to get a cached instance from that map, and if it doesn't exist, construct one and put it in the map.
I believe case classes only consider the arguments to their constructor (not any auxiliary constructor) to be part of their equality concept. Consider when you use a case class in a match statement, unapply only gives you access (by default) to the constructor parameters.
Consider anything in the body of case classes as "extra" or "side effect" stuffs. I consider it a good tactic to make case classes as near-empty as possible and put any custom logic in a companion object. Eg:
case class Foo(a:Int)
object Foo {
def apply(s: String) = Foo(s.toInt)
}
In addition to dhg answer, I should say, I'm not aware of functional language that does full constructor memoizing by default. You should understand that such memoizing means that all constructed instances should stick in memory, which is not always desirable.
Manual caching is not that hard, consider this simple code
import scala.collection.mutable
class Doubler private(a: Int) {
lazy val double = {
println("calculated")
a * 2
}
}
object Doubler{
val cache = mutable.WeakHashMap.empty[Int, Doubler]
def apply(a: Int): Doubler = cache.getOrElseUpdate(a, new Doubler(a))
}
Doubler(1).double //calculated
Doubler(5).double //calculated
Doubler(1).double //most probably not calculated

Scala - Conditionally add traits to class instance during construction

I'm trying create an instance of a class and mix in certain traits based on certain conditions. So Given:
class Foo
trait A
trait B
I can do something like
if (fooType == "A")
new Foo with A
else if (footType == "B")
new Foo With B
That works just fine for a simple case like this. My issue is that multiple traits can be mixed into the same instance based on other conditions, and on top of that the class being instantiated has a fair amount of parameters so this leads to a pretty ugly conditional block.
What I would like to do is determine the traits to be mixed in before hand something like this (which I know is not legal scala code):
val t1 = fooType match {
case "a" => A
case "b" => B
}
val t2 = fooScope match {
case "x" => X
case "y" => Y
}
new Foo with t1 with t2
Where A, B, X, and Y are all previously defined traits, and fooType and fooScope are inputs to my function. I'm not sure if there is anything I can do which is somewhat similar to the above, but any advice would be appreciated.
Thanks
I believe what you want to do is not possible. In Scala the type of an object has to be known at compile time, so new Foo with A works but new Foo with t1 will not because t1 is resolved only at run time.
A couple of ideas to throw in the mix...
Non-runtime Factory
With the complicated code full of conditionals that you speak of, get those to put together a list of possible combinations. This list can then be used to create all the classes. Very simple example:
(for(a <- Seq("A", "B"); b <- Seq("X", "Y")) yield
s"class Foo$a$b extends $a with $b").mkString("\n")
which'll produce the following:
class FooAX extends A with X
class FooBX extends B with X
class FooAY extends A with Y
class FooBY extends B with Y
Then simply:
val ax = new FooAX()
which is nice because it's very strongly typed and everyone'll know exactly what type it is everywhere without much casting/inference headache.
Delegation
There's an interesting non-reflection/classloader technique here:
https://github.com/b-studios/MixinComposition
which takes in traits as parameters and then simply delegate to the appropriate trait.

Scala implicit unapply

Am trying to implicitly deconstruct a class instance into a tuple to create a nicer DSL syntax.
Here's a simplified example of what I'm trying to do:
class Pair[A,B](a: A, b: B){
def left = a
def right = b
}
val pair = new Pair(1,2)
implicit def unpair[T1 <: Int, T2 <: Int](p: Pair[T1,T2]) = {
(p.left, p.right)
}
val(a,b) = pair
results in:
error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: Pair[Int,Int]
I know I can define a companion object with unapply method and manually handle the deconstruction (or call above implicit explicitly), but that makes for unwanted boilerplate.
Edit
Ok, just to provide a bit more context, Pair is embedded within an instance that implements map, flatMap, and withFilter (i.e. to be used within for comprehensions). So, desired usage looks something like:
val q = for{
(a,b) <- tableA join tableB on(...)
(c,d) <- tableC leftJoin tableD on(...)
....
} yield(a,b,c,d,...)
What I'd like to avoid is making Pair a case class (or adding a custom companion object to existing Pair class) and having to Pair(a,b) <- tableA join tableB on(...) everytime I join tables (read: often)
Original
Is there a way to pull this off in Scala 2.10 or 2.11?? There are some older SO threads from 2.8/2.9 days that indicate this functionality is not possible, but am hoping things have changed since then, or that there's a workaround available.
You need to set type of a and b explicit:
val(a,b): (Int, Int) = pair
If you just want to extract left and right (I'm guessing from your example), why not to solve your problem with even less code:
case class Pair[A, B](left: A, right: B)
val pair = Pair(1, 2)
val Pair(a, b) = pair
println(a, b)