Scala: How can I implement the clone method on a superclass and use it in a subclass?

Maybe I'm wrong, but I would like to have an object like this:

class MyDataStructure { def myClone = { val clone = new MyDataStructure // do stuff to make clone the same as this ... clone } } class MyDataStructureExtended(val foo: String) extends MyDataStructure 

Then:

 val data = MyDataStructureExtended val dataClone = data.clone println(dataClone.foo) 

So the problem is that dataClone is of type MyDataStructure, not MyDataStructureExtended, as I had hoped.

I thought about adding a type T to a superclass that a subclass can specify (for example, itself), but that didn't seem very promising.

+6
scala
source share
3 answers

Assuming you want to minimize the number of ceremonies in subclasses, here is my suggestion:

 class A extends Cloneable { protected[this] def myCloneImpl[T] = { val justLikeMe = this.clone // copy values and such. // Note that the Object.clone method already made a shallow copy, but you may want // to deepen the copy or do other operations. justLikeMe.asInstanceOf[T] } def myClone = myCloneImpl[A] } class B extends A { override def myClone = myCloneImpl[B] } 

By extending java.lang.Cloneable and calling the Object.clone method, you guarantee that your runtime type matches the cloned object. The static type is enforced with cast type (asInstanceOf [T]). You need to override the myClone method in each subclass and specify the type, but it must be single-line.

+4
source share

As you suggested, abstract types or general parameters are what you need. Do you need MyDataStructure not to be a sign or an abstract class? The following defines that MyDataStructure is an abstract class, but you can also make it a trait.

 abstract class MyDataStructure { type T def myClone: T } class MyDataStructureExtended(foo: String) extends MyDataStructure { type T = MyDataStructureExtended def myClone = new MyDataStructureExtended(foo) } 

Scala interpreter results show that the myClone method defined in MyDataStructureExtended is the correct type.

 scala> val mde = new MyDataStructureExtended("foo") val mde = new MyDataStructureExtended("foo") mde: MyDataStructureExtended = MyDataStructureExtended@3ff5d699 scala> val cloned = mde.myClone val cloned = mde.myClone cloned: MyDataStructureExtended = MyDataStructureExtended@2e1ed620 

You might want to restrict T so that its type can only be a subclass type of MyDataStructure

 abstract class MyDataStructure { type T <: MyDataStructure def myClone: T } 

I do not know your requirements, but I believe that Scala 2.8 will have nice functionality with case classes and named arguments that allow you to clone case classes using the copy method.

+5
source share

It’s hard to say if you are doing it right with such an indefinite description of the problem, but it’s actually quite simple to do it. You can simply override myclone in MyDataStructureExtended so that it returns a more specific type. When you have a variable of a more specific type, you can also use a more specific cloning method.

Sample code if this description is unclear:

 class A { def getMe = this } class B extends A { override def getMe = this def isAnInstanceOfB = true } 

And the corresponding REPL session:

 scala> val a = new A a: A = A@1a6eeab scala> val b = new B b: B = B@a36771 scala> a.getMe res0: A = A@1a6eeab scala> a.getMe.isAnInstanceOfB <console>:7: error: value isAnInstanceOfB is not a member of A a.getMe.isAnInstanceOfB ^ scala> b.isAnInstanceOfB res2: Boolean = true scala> b.getMe.isAnInstanceOfB res3: Boolean = true 
0
source share

All Articles