Polymorphic copy: Difference between revisions

Content added Content deleted
No edit summary
Line 2: Line 2:


It is trivial to copy an object if its type is known:
It is trivial to copy an object if its type is known:
<c>
<lang c>
int x;
int x;
int y = x;
int y = x;
</c>
</lang>
Here x is not polymorphic, so y is declared of same type (''int'') as x. But if the specific type of x were unknown, then y could not be declared of any specific type.
Here x is not polymorphic, so y is declared of same type (''int'') as x. But if the specific type of x were unknown, then y could not be declared of any specific type.


Line 11: Line 11:


=={{header|Ada}}==
=={{header|Ada}}==
<ada>
<lang ada>
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO; use Ada.Text_IO;


Line 54: Line 54:
Copier (Object_2);
Copier (Object_2);
end Test_Polymorphic_Copy;
end Test_Polymorphic_Copy;
</ada>
</lang>
The procedure Copier does not know the specific type of its argument. Nevertheless it creates an object Duplicate of exactly same type. Sample output:
The procedure Copier does not know the specific type of its argument. Nevertheless it creates an object Duplicate of exactly same type. Sample output:
<pre>
<pre>
Line 62: Line 62:


=={{header|C++}}==
=={{header|C++}}==
<cpp>
<lang cpp>
#include <iostream>
#include <iostream>


Line 113: Line 113:
copy.identify_member(); // and check what type of member it contains
copy.identify_member(); // and check what type of member it contains
}
}
</cpp>
</lang>


=={{header|Java}}==
=={{header|Java}}==
Here we implement a "copy" method once in the base class because there is by default no public way to copy an object from outside the class in Java. (There is a protected, not public, "clone" method inherited from Object.)
Here we implement a "copy" method once in the base class because there is by default no public way to copy an object from outside the class in Java. (There is a protected, not public, "clone" method inherited from Object.)
<java>class T implements Cloneable {
<lang java>class T implements Cloneable {
public String name() { return "T"; }
public String name() { return "T"; }
public T copy() {
public T copy() {
Line 140: Line 140:
System.out.println(copier(obj2).name()); // prints "S"
System.out.println(copier(obj2).name()); // prints "S"
}
}
}</java>
}</lang>


=={{header|OCaml}}==
=={{header|OCaml}}==
I decided not to use classes and inheritance here because structural subtyping is more natural in OCaml. Oo.copy is polymorphic over all object types.
I decided not to use classes and inheritance here because structural subtyping is more natural in OCaml. Oo.copy is polymorphic over all object types.
<ocaml>let obj1 =
<lang ocaml>let obj1 =
object
object
method name = "T"
method name = "T"
Line 156: Line 156:
let () =
let () =
print_endline (Oo.copy obj1)#name; (* prints "T" *)
print_endline (Oo.copy obj1)#name; (* prints "T" *)
print_endline (Oo.copy obj2)#name; (* prints "S" *)</ocaml>
print_endline (Oo.copy obj2)#name; (* prints "S" *)</lang>


=={{header|PHP}}==
=={{header|PHP}}==
<php><?php
<lang php><?php
class T {
class T {
function name() { return "T"; }
function name() { return "T"; }
Line 174: Line 174:
echo $obj3->name(), "\n"; // prints "T"
echo $obj3->name(), "\n"; // prints "T"
echo $obj4->name(), "\n"; // prints "S"
echo $obj4->name(), "\n"; // prints "S"
?></php>
?></lang>


=={{header|Python}}==
=={{header|Python}}==
<python>import copy
<lang python>import copy


class T:
class T:
Line 230: Line 230:
u.myValue = "Yellow"
u.myValue = "Yellow"
u.speak()
u.speak()
b.speak()</python>Output of the above program is as follows<pre>
b.speak()</lang>Output of the above program is as follows<pre>
creating initial objects of types S1, S2, and T
creating initial objects of types S1, S2, and T
S1 Meow Green
S1 Meow Green
Line 252: Line 252:
In many cases the most portable and robust "copy" would be made by serializing the source object and then de-serializing it back into the target. Under Python this would best be done with the ''pickle'' or ''cPickle''
In many cases the most portable and robust "copy" would be made by serializing the source object and then de-serializing it back into the target. Under Python this would best be done with the ''pickle'' or ''cPickle''


<python>
<lang python>
import cPickle as pickle
import cPickle as pickle


Line 260: Line 260:


target = pickle.loads(pickle.dumps(source))
target = pickle.loads(pickle.dumps(source))
</python>
</lang>


In this example we use the ''cPickle'' module which is an implementation of the pickle features coded in C for optimal performance. We import it as ''pickle'' since we intend to use only those features which are common to both implementations. (The pure Python implementation is retained for those who which to create their own classes derived therefrom). The ''dumps()'' and ''loads()'' methods dump the data structures to a string and load them from a string, respectively. (The more common use of ''pickle'' is to serialize the data out to a file or over a network connection using file-like ''.read()'' and ''.write()'' methods. For those we'd use the ''pickle.dump()'' and ''pickle.load()'' methods).
In this example we use the ''cPickle'' module which is an implementation of the pickle features coded in C for optimal performance. We import it as ''pickle'' since we intend to use only those features which are common to both implementations. (The pure Python implementation is retained for those who which to create their own classes derived therefrom). The ''dumps()'' and ''loads()'' methods dump the data structures to a string and load them from a string, respectively. (The more common use of ''pickle'' is to serialize the data out to a file or over a network connection using file-like ''.read()'' and ''.write()'' methods. For those we'd use the ''pickle.dump()'' and ''pickle.load()'' methods).
Line 266: Line 266:
For the simplest cases one can use simple Python introspection to copy simple objects:
For the simplest cases one can use simple Python introspection to copy simple objects:


<python>
<lang python>
target = source.__class__() # Create an object of the same type
target = source.__class__() # Create an object of the same type
if hasattr(source, 'items') and callable(source.items):
if hasattr(source, 'items') and callable(source.items):
Line 275: Line 275:
else: # Following is not recommended. (see below).
else: # Following is not recommended. (see below).
target = source
target = source
</python>
</lang>


This example handles dictionaries (and anything that implements a sufficiently dictionary like interface to support the ''items()'' method along with the ''__setitem__()'' method. (statements of the form '''''x[y] = z''''' in Python are implicitly calling the ''__setitem__()'' method of the "x" object, passing it a key of "y" and a value of "z." Similarly this code tests if an item is a sequence (one can call the "len()" built-in function on it) and, if so, uses a slice assignment to perform a shallow copy. For any other type of object a simple binding is performed. Technically this last case will not "copy" anything ... it will create a new name binding to the object to which "source" was already a reference. The earlier binding of a "blank" instance of the source's __class__ will be replaced. So the trick of creating the blank object of the same type is only meaningful for the other types. In the cases of strings, integers and other numbers the objects themselves are immutable and the bindings are all dynamic (so the entire task is moot with respect to them).
This example handles dictionaries (and anything that implements a sufficiently dictionary like interface to support the ''items()'' method along with the ''__setitem__()'' method. (statements of the form '''''x[y] = z''''' in Python are implicitly calling the ''__setitem__()'' method of the "x" object, passing it a key of "y" and a value of "z." Similarly this code tests if an item is a sequence (one can call the "len()" built-in function on it) and, if so, uses a slice assignment to perform a shallow copy. For any other type of object a simple binding is performed. Technically this last case will not "copy" anything ... it will create a new name binding to the object to which "source" was already a reference. The earlier binding of a "blank" instance of the source's __class__ will be replaced. So the trick of creating the blank object of the same type is only meaningful for the other types. In the cases of strings, integers and other numbers the objects themselves are immutable and the bindings are all dynamic (so the entire task is moot with respect to them).
Line 281: Line 281:
=={{header|Ruby}}==
=={{header|Ruby}}==
All Ruby objects inherit two methods for copying themselves: "clone" and "dup". I don't really understand the difference between them.
All Ruby objects inherit two methods for copying themselves: "clone" and "dup". I don't really understand the difference between them.
<ruby>class T
<lang ruby>class T
def name
def name
"T"
"T"
Line 296: Line 296:
obj2 = S.new
obj2 = S.new
puts obj1.dup.name # prints "T"
puts obj1.dup.name # prints "T"
puts obj2.dup.name # prints "S"</ruby>
puts obj2.dup.name # prints "S"</lang>