Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

scala

I might be approaching this the wrong way, but I'd 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'd hoped.

I thought about adding a type T to the super class, that the subclass can specify (e.g. itself), but that didn't seem very promising.

like image 722
Alex Black Avatar asked Jan 08 '10 03:01

Alex Black


People also ask

Which of the following is correct way to implement clone method?

Creating a copy using the clone() method The class whose object's copy is to be made must have a public clone method in it or in one of its parent class. Every class that implements clone() should call super. clone() to obtain the cloned object reference. The class must also implement java.

Which method should be used when overriding clone () of an object with mutable fields?

Utilize Object clone() method by calling super. clone() in overridden clone method, then make necessary changes for deep copying of mutable fields. If your class is serializable, you can use serialization for cloning.

What is super clone ()?

If a class which implements Cloneable does override the Object.clone() method, usually a super.clone() will be called first to make a binary copy of the original object and then deep copy will be performed accordingly based on the binary copy.

Which of the following options is the syntax of the clone () method?

The clone() method is defined in the Object class. Syntax of the clone() method is as follows: protected Object clone() throws CloneNotSupportedException.


2 Answers

As you have suggested, abstract types, or generic parameters, are what you need. Do you require that MyDataStructure not be a trait or abstract class? The following defines MyDataStructure to be an abstract class, but you can make it a trait as well.

abstract class MyDataStructure {
  type T
  def myClone: T
}

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

The results from the Scala interpreter 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 that of MyDataStructure subclasses

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

I don't know your requirements, but I believe that Scala 2.8 will have some nice functionality with case classes and named arguments that allow one to clone case classes with a copy method.

like image 109
faran Avatar answered Sep 21 '22 02:09

faran


Assuming you want to minimize amount of ceremony in the 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 ensure that your runtime type is the same as the object being cloned. The static type is coerced with a type-cast (asInstanceOf[T]). You will need to override the myClone method in each subclass and specify the type, but it should be a one-liner.

like image 34
Mitch Blevins Avatar answered Sep 20 '22 02:09

Mitch Blevins