Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing '.clone' in Scala

Tags:

scala

I'm trying to figure out how to .clone my own objects, in Scala.

This is for a simulation so mutable state is a must, and from that arises the whole need for cloning. I'll clone a whole state structure before moving the simulation time ahead.

This is my current try:

abstract trait Cloneable[A] {
  // Seems we cannot declare the prototype of a copy constructor
  //protected def this(o: A)    // to be defined by the class itself

  def myClone= new A(this)
}

class S(var x: String) extends Cloneable[S] {
  def this(o:S)= this(o.x)    // for 'Cloneable'
  def toString= x
}

object TestX {
  val s1= new S("say, aaa")
  println( s1.myClone )
}

a. Why does the above not compile. Gives:

error: class type required but A found
  def myClone= new A(this)
                   ^

b. Is there a way to declare the copy constructor (def this(o:A)) in the trait, so that classes using the trait would be shown to need to provide one.

c. Is there any benefit from saying abstract trait?

Finally, is there a way better, standard solution for all this?

I've looked into Java cloning. Does not seem to be for this. Also Scala copy is not - it's only for case classes and they shouldn't have mutable state.

Thanks for help and any opinions.

like image 675
akauppi Avatar asked Dec 06 '22 11:12

akauppi


2 Answers

Traits can't define constructors (and I don't think abstract has any effect on a trait).

Is there any reason it needs to use a copy constructor rather than just implementing a clone method? It might be possible to get out of having to declare the [A] type on the class, but I've at least declared a self type so the compiler will make sure that the type matches the class.

trait DeepCloneable[A] { self: A =>
    def deepClone: A
}

class Egg(size: Int) extends DeepCloneable[Egg] {
    def deepClone = new Egg(size)
}

object Main extends App {
    val e = new Egg(3)
    println(e)
    println(e.deepClone)
}

http://ideone.com/CS9HTW

like image 143
Nick Avatar answered Dec 28 '22 10:12

Nick


It would suggest a typeclass based approach. With this it is possible to also let existing classes be cloneable:

class Foo(var x: Int)

trait Copyable[A] {
  def copy(a: A): A
}

implicit object FooCloneable extends Copyable[Foo] {
  def copy(foo: Foo) = new Foo(foo.x)
}

implicit def any2Copyable[A: Copyable](a: A) = new {
  def copy = implicitly[Copyable[A]].copy(a)
}


scala> val x = new Foo(2)
x: Foo = Foo@8d86328

scala> val y = x.copy
y: Foo = Foo@245e7588

scala> x eq y
res2: Boolean = false
like image 20
drexin Avatar answered Dec 28 '22 10:12

drexin