Polymorphic copy: Difference between revisions

m
{{out}}
m ({{out}})
Line 1:
{{task|Object oriented}}
{{task|Object oriented}}An object is [[polymorphism|polymorphic]] when its specific type may vary. The types a specific value may take, is called ''class''.
The types a specific value may take, is called ''class''.
 
It is trivial to copy an object if its type is known:
<lang c>int x;
int y = x;</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.
But if the specific type of x were unknown, then y could not be declared of any specific type.
 
The task: let a polymorphic object contain an instance of some specific type S derived from a type T. The type T is known. The type S is possibly unknown until [[run time]]. The objective is to create an exact copy of such polymorphic object (not to create a [[reference]], nor a pointer to). Let further the type T have a method overridden by S. This method is to be called on the copy to demonstrate that the specific type of the copy is indeed S.
The type T is known.
The type S is possibly unknown until [[run time]].
The objective is to create an exact copy of such polymorphic object (not to create a [[reference]], nor a pointer to).
Let further the type T have a method overridden by S.
This method is to be called on the copy to demonstrate that the specific type of the copy is indeed S.
 
=={{header|Ada}}==
Line 62 ⟶ 70:
Put_Line ("Cloned " & Object_4.all.Name);
end Test_Polymorphic_Copy;</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:
Nevertheless it creates an object Duplicate of exactly same type.
{{out}}
<pre>
Copied T
Line 98 ⟶ 108:
 
</lang>
{{out}}
Output:
 
before copy
class T
Line 137 ⟶ 146:
PRINT result%
END</lang>
{{out}}
'''Output:'''
<pre>
15129
Line 143 ⟶ 152:
 
=={{header|C}}==
Since C doesn't support classes, this is not quite so trivial. Normally the code below
Normally the code below would be split into a number of files. Specificially there would be a header (.h) file and<br>
Specificially there would be a header (.h) file and a source (.c) file for each of - BaseObj, Dog, and Ferret. The code in "main" would also be<br>
The code in "main" would also be a separate source file which would include Dog.h and Ferret.h header files (which would thems elves include the BaseObj.h header file.)
elves include the BaseObj.h header file.) A better example of object oriented support in 'C' can be found in the source for the XtIntrinsics library of X11.
be found in the source for the XtIntrinsics library of X11.
<lang c>#include <stdio.h>
#include <stdlib.h>
Line 392 ⟶ 400:
}
}</lang>
{{out}}
Output:
<lang>S
S</lang>
Line 636 ⟶ 644:
[ clone ]
[ serial-clone ] bi [ class . ] bi@</lang>
{{out}}
outputs:
C
C
Line 719 ⟶ 727:
In addition to the types t and s called for by the task description, I define two other types:
 
i, an interface type, is needed as a common "base" definition for the method. This is not Go terminology, and in fact notice that i is not even referenced anywhere in the definitions of types s or t. A "parent" method definition is called for by the task however, and interfaces are Go's way of doing this.
This is not Go terminology, and in fact notice that i is not even referenced anywhere in the definitions of types s or t.
A "parent" method definition is called for by the task however, and interfaces are Go's way of doing this.
 
r, another type defined similarly to s, I added to illustrate that this analog of method inheritance and overriding is valid. (In Go terminology, that the method set of a type with an anonymous field includes the method set of the anonymous field.) You can see in the output that interface values of type r access t's identify method. Values of type s would as well, except s has it's own identify method which takes precedence.<br>
You can see in the output that interface values of type r access t's identify method.
Values of type s would as well, except s has it's own identify method which takes precedence.
<lang go>package main
 
Line 761 ⟶ 773:
 
// the same method on s. although s already satisfied i, calls to identify
// will now find this method rather than the one defined on t. in a sense
// in a sense it "overrides" the method of the "base class."
func (x s) identify() string {
return "I'm an s!"
Line 806 ⟶ 818:
fmt.Println("i3c:", i3c, "/", i3c.identify(), "/", reflect.TypeOf(i3c))
}</lang>
{{out}}
Output:
<pre>
Initial (zero) values of interface variables:
Line 863 ⟶ 875:
println "objB:: name: ${objB.name()}, property: ${objB.property}"</lang>
 
{{out}}
Output:
<pre>objA:: name: T, property: whatever
objB:: name: S, property: meh</pre>
Line 869 ⟶ 881:
=={{header|Icon}} and {{header|Unicon}}==
 
Icon and Unicon do no compile-time type checks. The deepcopy procedure from
The deepcopy procedure from the Deep Copy task is sufficient. The sample code shown below is
The sample code shown below is Unicon-specific only because it is copying an object (Icon has no object-oriented support).
object-oriented support). The deepcopy procedure is identical in both languages.
lanaguages.
 
<lang unicon>class T()
Line 921 ⟶ 932:
=={{header|J}}==
 
Most of the time, J will automatically make a copy for you on dereference. So expressions of the form
So expressions of the form
def=: abc
are sufficient.
Line 943 ⟶ 955:
 
=={{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.) The way to clone polymorphically is to obtain a copy from the superclass's <code>clone()</code> method, and then perform custom copying operations specific to this class. If this pattern is followed, the calls will eventually pass all the way up to <code>Object</code>'s <code>clone()</code> method, which performs a polymorphic copy. If you do not follow this pattern, and simply use a constructor, like <code>new T()</code>, then the copy won't be polymorphic.
The way to clone polymorphically is to obtain a copy from the superclass's <code>clone()</code> method, and then perform custom copying operations specific to this class.
If this pattern is followed, the calls will eventually pass all the way up to <code>Object</code>'s <code>clone()</code> method, which performs a polymorphic copy.
If you do not follow this pattern, and simply use a constructor, like <code>new T()</code>, then the copy won't be polymorphic.
<lang java>class T implements Cloneable {
public String name() { return "T"; }
Line 1,049 ⟶ 1,064:
u.speak
b.speak</lang>
{{out}}
Output:
<pre>creating initial objects of types S1, S2, and T
S1 Meow Green
Line 1,068 ⟶ 1,083:
 
=={{header|Objective-C}}==
All objects inherit the <code>copy</code> method from <code>NSObject</code>, which performs copying. But they must implement the <code>NSCopying</code> protocol (which involves implementing the <code>copyWithZone:</code> method) to actually specify how to copy. Calling <code>copy</code> on an object that does not implement <code>copyWithZone:</code> will result in an error.
But they must implement the <code>NSCopying</code> protocol (which involves implementing the <code>copyWithZone:</code> method) to actually specify how to copy.
Calling <code>copy</code> on an object that does not implement <code>copyWithZone:</code> will result in an error.
 
Generally, to implement copying, if your parent class does not implement <code>NSCopying</code>, you explicitly allocate a new object (using the class object <code>[self class]</code> instead of hard-coding the name of a particular class, in order to be polymorphic), and initialize it with your object's data. If your parent class already implements <code>NSCopying</code>, and you wish to customize the copying of your class's fields, then you should get a copy from your parent object's <code>copyWithZone:</code> method, and then perform custom initialization on the copy.
If your parent class already implements <code>NSCopying</code>, and you wish to customize the copying of your class's fields, then you should get a copy from your parent object's <code>copyWithZone:</code> method, and then perform custom initialization on the copy.
 
<lang objc>@interface T : NSObject
Line 1,111 ⟶ 1,129:
}</lang>
 
Analogously, there is a <code>mutableCopy</code> method to get a mutable copy of the current object (e.g. if you have an NSArray object and you want an NSMutableArray with the same contents). In this case it would have to implement the <code>NSMutableCopying</code> protocol (which involves implementing the <code>mutableCopyWithZone:</code> method) to specify how to copy.
In this case it would have to implement the <code>NSMutableCopying</code> protocol (which involves implementing the <code>mutableCopyWithZone:</code> method) to specify how to copy.
 
=={{header|OCaml}}==
Line 1,231 ⟶ 1,250:
{Obj getA($)} \= {Copy getA($)} = true</lang>
 
Oz is not a pure object-oriented language. In fact, most values are not objects. For immutable data it usually does not make sense to clone it because it does not have an identity beyond its value. For mutable data types there are clone functions available (<code>Dictionary.clone</code>, <code>Array.clone</code>, <code>BitArray.clone</code>).
For immutable data it usually does not make sense to clone it because it does not have an identity beyond its value.
For mutable data types there are clone functions available (<code>Dictionary.clone</code>, <code>Array.clone</code>, <code>BitArray.clone</code>).
 
=={{header|Perl}}==
Line 1,390 ⟶ 1,411:
u.myValue = "Yellow"
u.speak()
b.speak()</lang>Output of the above program is as follows<pre>
{{out}}
creating initial objects of types S1, S2, and T
S1 Meow Green
Line 1,408 ⟶ 1,430:
S2 Woof Yellow</pre>
 
The foregoing example uses the Python standard library ''copy'' module.
The foregoing example uses the Python standard library ''copy'' module. The task, as stated,does not provide insight as to what should happen should the object contain lists of other objects. It could be necessary to use "deep copy" instead of copy. (using ''copy.deepcopy''). The distinction is important for complex objects containing references to other objects (for instances lists, tuples or dictionaries containing other lists, tuples or dictionaries as elements). The described task, as presented, offers no guidance on this matter.
The task, as stated,does not provide insight as to what should happen should the object contain lists of other objects.
It could be necessary to use "deep copy" instead of copy. (using ''copy.deepcopy'').
The distinction is important for complex objects containing references to other objects (for instances lists, tuples or dictionaries containing other lists, tuples or dictionaries as elements).
The described task, as presented, offers no guidance on this matter.
 
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'' standard modules.
Under Python this would best be done with the ''pickle'' or ''cPickle'' standard modules.
 
<lang python>import cPickle as pickle
Line 1,420 ⟶ 1,447:
target = pickle.loads(pickle.dumps(source))</lang>
 
In this example we use the ''cPickle'' module which is an implementation of the pickle features coded in C for optimal performance.
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).
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).
 
For the simplest cases one can use simple Python introspection to copy simple objects:
Line 1,433 ⟶ 1,464:
target = source</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).
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).
 
=={{header|Racket}}==
Line 1,518 ⟶ 1,555:
 
=={{header|Ruby}}==
All Ruby objects inherit two methods for copying themselves: "clone" and "dup". I don't really understand the difference between them.
I don't really understand the difference between them.
<lang ruby>class T
def name
Line 1,538 ⟶ 1,576:
=={{header|Slate}}==
 
All objects in Slate may be <tt>clone</tt>d unless they are clones of <tt>Oddball</tt> (like <tt>True</tt>, <tt>False</tt>, and <tt>Nil</tt>) or are word-size Integers (which are encoded as tagged pointer values). This is a shallow copy where no values held in the object's slots are replaced with copies. There is also a <tt>copy</tt> method which is universal and overridden to perform deep copies as appropriate - copying continues via recursion through slot values and should be modified on any type where equality (<tt>=</tt>) is overridden.
This is a shallow copy where no values held in the object's slots are replaced with copies.
There is also a <tt>copy</tt> method which is universal and overridden to perform deep copies as appropriate - copying continues via recursion through slot values and should be modified on any type where equality (<tt>=</tt>) is overridden.
 
<lang slate>define: #T &parents: {Cloneable}.
Line 1,577 ⟶ 1,617:
 
=={{header|Tcl}}==
Tcl values are logically immutable, and are passed around by reference with copies being taken as and when it is necessary to do so to maintain the immutable model. Hence an effective copy of any value is just:
Hence an effective copy of any value is just:
<lang tcl>set varCopy $varOriginal</lang>
With objects, slightly more work is required because they are normally passed around by name/reference.
Line 1,624 ⟶ 1,665:
$obj2 print
$obj1 print</lang>
Which produces this output{{out}} (object names might vary if you run it):
<pre>
this is Abracadabra in ::oo::Obj5, stepped 2 times
Anonymous user