Polymorphic copy: Difference between revisions
Converted both D entries from D1+Tango => D2+Phobos (I can't test Tango code) |
→{{header|Perl 6}}: add entry |
||
Line 1,057: | Line 1,057: | ||
print "\$x is: "; |
print "\$x is: "; |
||
$x->manifest;</lang> |
$x->manifest;</lang> |
||
=={{header|Perl 6}}== |
|||
<lang perl6>my Cool $x = 22/7 but role Fink { method brag { say "I'm a cool {self.WHAT.perl}!" }} |
|||
my Cool $y = $x.clone; |
|||
$y.brag;</lang> |
|||
{{out}} |
|||
<pre>I'm a cool Rat+Fink!</pre> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
Revision as of 02:04, 24 February 2013
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
An object is polymorphic when its specific type may vary. 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.
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.
Ada
<lang ada>with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Polymorphic_Copy is
package Base is type T is tagged null record; function Name (X : T) return String; end Base; use Base; package body Base is function Name (X : T) return String is begin return "T"; end Name; end Base; -- The procedure knows nothing about S procedure Copier (X : T'Class) is Duplicate : T'Class := X; -- A copy of X begin Put_Line ("Copied " & Duplicate.Name); -- Check the copy end Copier;
package Derived is type S is new T with null record; overriding function Name (X : S) return String; end Derived; use Derived; package body Derived is function Name (X : S) return String is begin return "S"; end Name; end Derived;
Object_1 : T; Object_2 : S;
begin
Copier (Object_1); Copier (Object_2);
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:
Copied T Copied S
Aikido
Aikido has a native clone
function that creates a (deep or shallow) clone of any variable of any type.
<lang aikido>
class T {
public function print { println ("class T") }
}
class S extends T {
public function print { println ("class S") }
}
var t = new T() var s = new S() println ("before copy") t.print() s.print()
var tcopy = clone (t, false) var scopy = clone (s, false) println ("after copy") tcopy.print() scopy.print()
</lang> Output:
before copy class T class S after copy class T class S
BBC BASIC
<lang bbcbasic> INSTALL @lib$ + "CLASSLIB"
REM Create parent class T: DIM classT{array#(0), setval, retval} DEF classT.setval (n%,v) classT.array#(n%) = v : ENDPROC DEF classT.retval (n%) = classT.array#(n%) PROC_class(classT{}) REM Create class S derived from T, known only at run-time: RunTimeSize% = RND(100) DIM classS{array#(RunTimeSize%)} PROC_inherit(classS{}, classT{}) DEF classS.retval (n%) = classS.array#(n%) ^ 2 : REM Overridden method PROC_class(classS{}) REM Create an instance of class S: PROC_new(myobject{}, classS{}) REM Now make a copy of the instance: DIM mycopy{} = myobject{} mycopy{} = myobject{} PROC_discard(myobject{}) REM Test the copy (should print 123^2): PROC(mycopy.setval)(RunTimeSize%, 123) result% = FN(mycopy.retval)(RunTimeSize%) PRINT result% END</lang>
Output:
15129
C
Since C doesn't support classes, this is not quite so trivial. Normally the code below would be split into a number of files. 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 a separate source file which would include Dog.h and Ferret.h header files (which would thems 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. <lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
typedef struct object *BaseObj; typedef struct sclass *Class; typedef void (*CloneFctn)(BaseObj s, BaseObj clo); typedef const char * (*SpeakFctn)(BaseObj s); typedef void (*DestroyFctn)(BaseObj s);
typedef struct sclass {
size_t csize; /* size of the class instance */ const char *cname; /* name of the class */ Class parent; /* parent class */
CloneFctn clone; /* clone function */ SpeakFctn speak; /* speak function */ DestroyFctn del; /* delete the object */
} sClass;
typedef struct object {
Class class;
} SObject;
static BaseObj obj_copy( BaseObj s, Class c ) {
BaseObj clo; if (c->parent) clo = obj_copy( s, c->parent); else clo = malloc( s->class->csize );
if (clo) c->clone( s, clo ); return clo;
}
static void obj_del( BaseObj s, Class c ) {
if (c->del) c->del(s); if (c->parent) obj_del( s, c->parent); else free(s);
}
BaseObj ObjClone( BaseObj s ) { return obj_copy( s, s->class ); }
const char * ObjSpeak( BaseObj s ) {
return s->class->speak(s);
}
void ObjDestroy( BaseObj s ) { if (s) obj_del( s, s->class ); }
/* * * * * * */ static void baseClone( BaseObj s, BaseObj clone) {
clone->class = s->class;
}
static const char *baseSpeak(BaseObj s) {
return "Hello, I'm base object";
}
sClass boc = { sizeof(SObject), "BaseObj", NULL,
&baseClone, &baseSpeak, NULL };
Class BaseObjClass = &boc;
/* * * * * * */ /* Dog - a derived class */
typedef struct sDogPart {
double weight; char color[32]; char name[24];
} DogPart;
typedef struct sDog *Dog;
struct sDog {
Class class; // parent structure DogPart dog;
};
static void dogClone( BaseObj s, BaseObj c) {
Dog src = (Dog)s; Dog clone = (Dog)c; clone->dog = src->dog; /* no pointers so strncpys not needed */
}
static const char *dogSpeak( BaseObj s) {
Dog d = (Dog)s; static char response[90]; sprintf(response, "woof! woof! My name is %s. I'm a %s %s", d->dog.name, d->dog.color, d->class->cname); return response;
}
sClass dogc = { sizeof(struct sDog), "Dog", &boc,
&dogClone, &dogSpeak, NULL };
Class DogClass = &dogc;
BaseObj NewDog( const char *name, const char *color, double weight ) {
Dog dog = malloc(DogClass->csize); if (dog) { DogPart *dogp = &dog->dog; dog->class = DogClass; dogp->weight = weight; strncpy(dogp->name, name, 23); strncpy(dogp->color, color, 31); } return (BaseObj)dog;
}
/* * * * * * * * * */ /* Ferret - a derived class */
typedef struct sFerretPart {
char color[32]; char name[24]; int age;
} FerretPart;
typedef struct sFerret *Ferret;
struct sFerret {
Class class; // parent structure FerretPart ferret;
};
static void ferretClone( BaseObj s, BaseObj c) {
Ferret src = (Ferret)s; Ferret clone = (Ferret)c; clone->ferret = src->ferret; /* no pointers so strncpys not needed */
}
static const char *ferretSpeak(BaseObj s) {
Ferret f = (Ferret)s; static char response[90]; sprintf(response, "My name is %s. I'm a %d mo. old %s wiley %s", f->ferret.name, f->ferret.age, f->ferret.color, f->class->cname); return response;
}
sClass ferretc = { sizeof(struct sFerret), "Ferret", &boc,
&ferretClone, &ferretSpeak, NULL };
Class FerretClass = &ferretc;
BaseObj NewFerret( const char *name, const char *color, int age ) {
Ferret ferret = malloc(FerretClass->csize); if (ferret) { FerretPart *ferretp = &(ferret->ferret); ferret->class = FerretClass; strncpy(ferretp->name, name, 23); strncpy(ferretp->color, color, 31); ferretp->age = age; } return (BaseObj)ferret;
}
/* * Now you really understand why Bjarne created C++ * */
int main() {
BaseObj o1; BaseObj kara = NewFerret( "Kara", "grey", 15 ); BaseObj bruce = NewDog("Bruce", "yellow", 85.0 ); printf("Ok created things\n");
o1 = ObjClone(kara ); printf("Karol says %s\n", ObjSpeak(o1)); printf("Kara says %s\n", ObjSpeak(kara)); ObjDestroy(o1);
o1 = ObjClone(bruce ); strncpy(((Dog)o1)->dog.name, "Donald", 23); printf("Don says %s\n", ObjSpeak(o1)); printf("Bruce says %s\n", ObjSpeak(bruce)); ObjDestroy(o1); return 0;
}</lang>
C#
<lang csharp>using System;
class T {
public virtual string Name() { return "T"; }
public virtual T Clone() { return new T(); }
}
class S : T {
public override string Name() { return "S"; }
public override T Clone() { return new S(); }
}
class Program {
static void Main() { T original = new S(); T clone = original.Clone();
Console.WriteLine(original.Name()); Console.WriteLine(clone.Name()); }
}</lang> Output: <lang>S S</lang>
C++
<lang cpp>#include <iostream>
class T { public:
virtual void identify() { std::cout << "I am a genuine T" << std::endl; } virtual T* clone() { return new T(*this); } virtual ~T() {}
};
class S: public T { public:
virtual void identify() { std::cout << "I am an S" << std::endl; } virtual S* clone() { return new S(*this); }
};
class X // the class of the object which contains a T or S { public:
// by getting the object through a pointer to T, X cannot know if it's an S or a T X(T* t): member(t) {}
// copy constructor X(X const& other): member(other.member->clone()) {}
// copy assignment operator X& operator=(X const& other) { T* new_member = other.member->clone(); delete member; member = new_member; }
// destructor ~X() { delete member; }
// check what sort of object it contains void identify_member() { member->identify(); }
private:
T* member;
};
int main() {
X original(new S); // construct an X and give it an S, X copy = original; // copy it, copy.identify_member(); // and check what type of member it contains
}</lang>
Common Lisp
With Structures
With structures, copy-structure
performs the right kind of copy. The object and its copy are compared under eq
, eql
, equal
, and equalp
to demonstrate that "The objective is to create an exact copy of such polymorphic object (not to create a reference, nor a pointer to)."
<lang lisp>(defstruct super foo)
(defstruct (sub (:include super)) bar)
(defgeneric frob (thing))
(defmethod frob ((super super))
(format t "~&Super has foo = ~w." (super-foo super)))
(defmethod frob ((sub sub))
(format t "~&Sub has foo = ~w, bar = ~w." (sub-foo sub) (sub-bar sub)))</lang>
> (let* ((sub1 (make-sub :foo 'foo :bar 'bar)) (sub2 (copy-structure sub1))) (frob sub1) (frob sub2) (format t "~&eq: ~w; eql: ~w; equal: ~w; equalp: ~w" (eq sub1 sub2) (eql sub1 sub2) (equal sub1 sub2) (equalp sub1 sub2))) Sub has foo = FOO, bar = BAR. Sub has foo = FOO, bar = BAR. eq: NIL; eql: NIL; equal: NIL; equalp: T NIL
With Sequences
The same technique works for sequence
and its subclasses (e.g., string
, list
) when copy-seq
is used rather than copy-structure
.
<lang lisp>(defmethod frob ((sequence sequence))
(format t "~&sequence has ~w elements" (length sequence)))
(defmethod frob ((string string))
(format t "~&the string has ~w elements" (length string)))</lang>
> (let* ((hw1 "hello world") (hw2 (copy-seq hw1))) (frob hw1) (frob hw2) (format t "~&eq: ~w; eql: ~w; equal: ~w; equalp: ~w" (eq hw1 hw2) (eql hw1 hw2) (equal hw1 hw2) (equalp hw1 hw2))) the string has 11 elements the string has 11 elements eq: NIL; eql: NIL; equal: T; equalp: T NIL
D
If we assume there are no data members, this will be quite short and simple: <lang d>class T {
override string toString() { return "I'm the instance of T"; } T duplicate() { return new T; }
}
class S : T {
override string toString() { return "I'm the instance of S"; }
override T duplicate() { return new S; }
}
void main () {
import std.stdio; T orig = new S; T copy = orig.duplicate();
writeln(orig); writeln(copy);
}</lang>
- Output:
I'm the instance of S I'm the instance of S
However this doesn't happen often in reality. If we want to copy data fields we should have something like copy constructor, that will do the deep copy. <lang d>class T {
this(T t = null) {} // Constructor that will be used for copying.
override string toString() { return "I'm the instance of T"; }
T duplicate() { return new T(this); }
bool custom(char c) { return false; }
}
class S : T {
char[] str;
this(S s = null) { super(s); if (s is null) str = ['1', '2', '3']; // All newly created will get that. else str = s.str.dup; // Do the deep-copy. }
override string toString() { return "I'm the instance of S p: " ~ cast(string)str; }
override T duplicate() { return new S(this); }
// Additional procedure, just to test deep-copy. override bool custom(char c) { if (str !is null) str[0] = c; return str is null; }
}
void main () {
import std.stdio; T orig = new S; orig.custom('X');
T copy = orig.duplicate(); orig.custom('Y');
writeln(orig); writeln(copy); // Should have 'X' at the beginning.
}</lang>
- Output:
I'm the instance of S p: Y23 I'm the instance of S p: X23
E
In E, a generic copy for all objects can be built out of the serialization facility, by connecting an object recognizer to an object builder without even using any intermediate serialized form:
<lang e>def deSubgraphKit := <elib:serial.deSubgraphKit>
def copy(object) {
return deSubgraphKit.recognize(object, deSubgraphKit.makeBuilder())
}</lang>
Since E does not have any static dispatch, this cannot be non-polymorphic without also being non-generic.
An example showing that it does indeed make copies follows. (For the task description, let S be the type of all serializable E objects, T be the FlexList
type (result of diverge
), and the overriden method be push
.
<lang e>? def a := [1].diverge()
- value: [1].diverge()
? def b := copy(a)
- value: [1].diverge()
? b.push(2) ? a
- value: [1].diverge()
? b
- value: [1, 2].diverge()</lang>
See also: Deepcopy#E
F#
.NET objects have a protected method MemberwiseClone
. This method creates a shallow copy of an object. Value type members are copied, i.e. not shared between clones. Reference type members, on the other hand, will reference the same objects after cloning.
<lang fsharp>type T() =
// expose protected MemberwiseClone method (and downcast the result) member x.Clone() = x.MemberwiseClone() :?> T // virtual method Print with default implementation abstract Print : unit -> unit default x.Print() = printfn "I'm a T!"
type S() =
inherit T() override x.Print() = printfn "I'm an S!"
let s = new S() let s2 = s.Clone() // the static type of s2 is T, but it "points" to an S s2.Print() // prints "I'm an S!"</lang>
Factor
shallow copy is achieved with the "clone" word. Deep copy is achieved with the serializing words "object>bytes" and "bytes>object".
Pasting the following in a repl: <lang factor>USING: classes kernel prettyprint serialize ; TUPLE: A ; TUPLE: C < A ;
- serial-clone ( obj -- obj' ) object>bytes bytes>object ;
C new [ clone ] [ serial-clone ] bi [ class . ] bi@</lang> outputs:
C C
Go
Go does not have the terminology of polymorphism, classes, inheritance, derived types, or overriding.
It does however, have types, structs, interfaces, and methods. These language features are expressive enough to allow this task to be implemented.
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.
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. <lang go>package main
import (
"fmt" "reflect"
)
// interface types provide polymorphism, but not inheritance. type i interface {
identify() string
}
// "base" type type t float64
// "derived" type. in Go terminology, it is simply a struct with an // anonymous field. fields and methods of anonymous fields however, // can be accessed without additional qualification and so are // "inherited" in a sense. type s struct {
t kōan string
}
// another type with an "embedded" t field. (t is the *type*, this field // has no *name*.) type r struct {
t ch chan int
}
// a method on t. this method makes t satisfy interface i. // since a t is embedded in types s and r, they automatically "inherit" // the method. func (x t) identify() string {
return "I'm a t!"
}
// 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 // it "overrides" the method of the "base class." func (x s) identify() string {
return "I'm an s!"
}
func main() {
// three variables with different types, initialized from literals. var t1 t = 5 var s1 s = s{6, "one"} var r1 r = r{t: 7}
// variables declared with the same type. initial value is nil. var i1, i2, i3 i fmt.Println("Initial (zero) values of interface variables:") fmt.Println("i1:", i1) fmt.Println("i2:", i2) fmt.Println("i3:", i3)
// in the terminology of the Go language reference, i1, i2, and i3 // still have static type i, but now have different dynamic types. i1, i2, i3 = t1, s1, r1 fmt.Println("\nPolymorphic:") fmt.Println("i1:", i1, "/", i1.identify(), "/", reflect.TypeOf(i1)) fmt.Println("i2:", i2, "/", i2.identify(), "/", reflect.TypeOf(i2)) fmt.Println("i3:", i3, "/", i3.identify(), "/", reflect.TypeOf(i3))
// copy: declare and assign in one step using "short declaration." i1c, i2c, i3c := i1, i2, i3
// modify first set of polymorphic variables. i1, i2, i3 = s{3, "dog"}, r{t: 1}, t(2)
// demonstrate that copies are distinct from first set // and that types are preserved. fmt.Println("\nFirst set now modified:") fmt.Println("i1:", i1, "/", i1.identify(), "/", reflect.TypeOf(i1)) fmt.Println("i2:", i2, "/", i2.identify(), "/", reflect.TypeOf(i2)) fmt.Println("i3:", i3, "/", i3.identify(), "/", reflect.TypeOf(i3))
fmt.Println("\nCopies made before modifications:") fmt.Println("i1c:", i1c, "/", i1c.identify(), "/", reflect.TypeOf(i1c)) fmt.Println("i2c:", i2c, "/", i2c.identify(), "/", reflect.TypeOf(i2c)) fmt.Println("i3c:", i3c, "/", i3c.identify(), "/", reflect.TypeOf(i3c))
}</lang> Output:
Initial (zero) values of interface variables: i1: <nil> i2: <nil> i3: <nil> Polymorphic: i1: 5 / I'm a t! / main.t i2: {6 one} / I'm an s! / main.s i3: {7 0x0} / I'm a t! / main.r First set now modified: i1: {3 dog} / I'm an s! / main.s i2: {1 0x0} / I'm a t! / main.r i3: 2 / I'm a t! / main.t Copies made before modifications: i1c: 5 / I'm a t! / main.t i2c: {6 one} / I'm an s! / main.s i3c: {7 0x0} / I'm a t! / main.r
J
Most of the time, J will automatically make a copy for you on dereference. So expressions of the form
def=: abc
are sufficient.
However, if you are working with mapped files, this lazy copy mechanism does not work, and neither will the built in identify functions. In those cases, you can use
def=: {.,: abc
Note that objects cannot be dereferenced. If you need polymorphic copy in J, you probably should not be using objects for that purpose.
JavaScript
Copied from here: <lang javascript>function clone(obj){
if (obj == null || typeof(obj) != 'object') return obj;
var temp = {}; for (var key in obj) temp[key] = clone(obj[key]); return temp;
}</lang>
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 clone()
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 Object
's clone()
method, which performs a polymorphic copy. If you do not follow this pattern, and simply use a constructor, like new T()
, then the copy won't be polymorphic.
<lang java>class T implements Cloneable {
public String name() { return "T"; } public T copy() { try { return (T)super.clone(); } catch (CloneNotSupportedException e) { return null; } }
}
class S extends T {
public String name() { return "S"; }
}
public class PolymorphicCopy {
public static T copier(T x) { return x.copy(); } public static void main(String[] args) { T obj1 = new T(); S obj2 = new S(); System.out.println(copier(obj1).name()); // prints "T" System.out.println(copier(obj2).name()); // prints "S" }
}</lang>
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref savelog symbols binary
-- ----------------------------------------------------------------------------- class RCPolymorphicCopy public
method copier(x = T) public static returns T
return x.copy
method main(args = String[]) public constant
obj1 = T() obj2 = S() System.out.println(copier(obj1).name) -- prints "T" System.out.println(copier(obj2).name) -- prints "S" return
-- ----------------------------------------------------------------------------- class RCPolymorphicCopy.T public implements Cloneable
method name returns String
return T.class.getSimpleName
method copy public returns T
dup = T
do dup = T super.clone catch ex = CloneNotSupportedException ex.printStackTrace end
return dup
-- ----------------------------------------------------------------------------- class RCPolymorphicCopy.S public extends RCPolymorphicCopy.T
method name returns String
return S.class.getSimpleName
</lang>
Objective-C
All objects inherit the copy
method from NSObject
, which performs copying. But they must implement the NSCopying
protocol (which involves implementing the copyWithZone:
method) to actually specify how to copy. Calling copy
on an object that does not implement copyWithZone:
will result in an error.
Implementing copying could be done with the NSCopyObject()
function for a simple byte-for-byte shallow copy of the object fields. However, due to it not respecting memory management of object pointer fields, this function is listed in the docs as "very difficult to use correctly", and "likely to be deprecated after Mac OS X 10.6". See this article for reasons why it this function is problematic.
Generally, to implement copying, if your parent class does not implement NSCopying
, you explicitly allocate a new object (using the class object [self class]
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 NSCopying
, and you wish to customize the copying of your class's fields, then you should get a copy from your parent object's copyWithZone:
method, and then perform custom initialization on the copy.
<lang objc>@interface T : NSObject { } - (void)identify; @end
@implementation T - (void)identify {
NSLog(@"I am a genuine T");
} - (id)copyWithZone:(NSZone *)zone {
T *copy = [[[self class] allocWithZone:zone] init]; // call an appropriate constructor here // then copy data into it as appropriate here // make sure to use "[[self class] alloc..." and // not "[T alloc..." to make it polymorphic return copy;
} @end
@interface S : T { } @end
@implementation S - (void)identify {
NSLog(@"I am an S");
} @end
int main() {
T *original = [[S alloc] init]; T *another = [original copy]; [another identify]; // logs "I am an S"
[another release]; // like "alloc", the object returned by "copy" is "owned" by the caller, so we are responsible for releasing it [original release]; return 0;
}</lang>
Analogously, there is a mutableCopy
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 NSMutableCopying
protocol (which involves implementing the mutableCopyWithZone:
method) to specify how to copy.
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. <lang ocaml>let obj1 =
object method name = "T" end
let obj2 =
object method name = "S" end
let () =
print_endline (Oo.copy obj1)#name; (* prints "T" *) print_endline (Oo.copy obj2)#name; (* prints "S" *)</lang>
ooRexx
All ooRexx objects have a copy method inherited from the object class that performs a shallow copy of the object state. <lang ooRexx> s = .s~new s2 = s~copy -- makes a copy of the first if s == s2 then say "copy didn't work!" if s2~name == "S" then say "polymorphic copy worked"
- class t
- method name
return "T"
- class s subclass t
- method name
return "S"
</lang>
OxygenBasic
<lang oxygenbasic> '====== class T '======
float vv
method constructor(float a=0) {vv=a} method destructor {} method copy as T {new T ob : ob<=vv : return ob} method mA() as float {return vv*2} method mB() as float {return vv*3}
end class
'======
class S
'======
has T
method mB() as float {return vv*4} 'ovveride
end class
'==== 'TEST '====
new T objA(10.5)
let objB = cast S objA.copy
print objA.mb 'result 31.5 print objB.mb 'result 42
del objA : del objB </lang>
Oz
We need to derive from the class ObjectSupport.reflect
in order to have a clone
method.
<lang oz>declare
class T from ObjectSupport.reflect meth init skip end
meth name($) 'T' end end
class S from T attr a feat f meth name($) 'S' end
meth getA($) @a end meth setA(V) a := V end end
Obj = {New S init} Copy = {Obj clone($)}
in
%% Some assertions:
%% Copy is really an S: {Copy name($)} = 'S'
%% Copy is not just a reference to the same object: {System.eq Obj Copy} = false
%% Not a deep copy. Feature f has the same identity for both objects: {System.eq Obj.f Copy.f} = true
%% However, both have their own distinct attributes: {Obj setA(13)} {Copy setA(14)} {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 (Dictionary.clone
, Array.clone
, BitArray.clone
).
Perl
<lang Perl>package T; sub new {
my $cls = shift; bless [ @_ ], $cls
}
sub set_data {
my $self = shift; @$self = @_;
}
sub copy {
my $self = shift; bless [ @$self ], ref $self;
}
sub manifest {
my $self = shift; print "type T, content: @$self\n\n";
}
package S; our @ISA = 'T';
- S is inheriting from T.
- 'manifest' method is overriden, while 'new', 'copy' and
- 'set_data' are all inherited.
sub manifest {
my $self = shift; print "type S, content: @$self\n\n";
}
package main;
print "# creating \$t as a T\n"; my $t = T->new('abc'); $t->manifest;
print "# creating \$s as an S\n"; my $s = S->new('SPQR'); $s->manifest;
print "# make var \$x as a copy of \$t\n"; my $x = $t->copy; $x->manifest;
print "# now as a copy of \$s\n"; $x = $s->copy; $x->manifest;
print "# show that this copy is indeed a separate entity\n"; $x->set_data('totally different'); print "\$x is: "; $x->manifest;</lang>
Perl 6
<lang perl6>my Cool $x = 22/7 but role Fink { method brag { say "I'm a cool {self.WHAT.perl}!" }} my Cool $y = $x.clone; $y.brag;</lang>
- Output:
I'm a cool Rat+Fink!
PHP
<lang php><?php class T {
function name() { return "T"; }
}
class S {
function name() { return "S"; }
}
$obj1 = new T(); $obj2 = new S(); $obj3 = clone $obj1; $obj4 = clone $obj2; echo $obj3->name(), "\n"; // prints "T" echo $obj4->name(), "\n"; // prints "S" ?></lang>
PicoLisp
Any object can be copied by transferring the value and the property list. If we create an object 'A': <lang PicoLisp>: (setq A (new '(+Cls1 +Cls2) 'attr1 123 'attr2 "def" 'attr3 (4 2 0) 'attr4 T)) -> $385603635
- (show A)
$385603635 (+Cls1 +Cls2)
attr4 attr3 (4 2 0) attr2 "def" attr1 123
-> $385603635</lang> Then we can easily copy it to a new object 'B': <lang PicoLisp>(putl (setq B (new (val A))) (getl A))</lang> Inspecting 'B': <lang PicoLisp>: (show B) $385346595 (+Cls1 +Cls2)
attr1 123 attr2 "def" attr3 (4 2 0) attr4
-> $385346595</lang>
Python
<lang python>import copy
class T:
def classname(self): return self.__class__.__name__
def __init__(self): self.myValue = "I'm a T."
def speak(self): print self.classname(), 'Hello', self.myValue
def clone(self): return copy.copy(self)
class S1(T):
def speak(self): print self.classname(),"Meow", self.myValue
class S2(T):
def speak(self): print self.classname(),"Woof", self.myValue
print "creating initial objects of types S1, S2, and T"
a = S1()
a.myValue = 'Green'
a.speak()
b = S2() b.myValue = 'Blue' b.speak()
u = T() u.myValue = 'Purple' u.speak()
print "Making copy of a as u, colors and types should match" u = a.clone() u.speak() a.speak() print "Assigning new color to u, A's color should be unchanged." u.myValue = "Orange" u.speak() a.speak()
print "Assigning u to reference same object as b, colors and types should match" u = b u.speak() b.speak() print "Assigning new color to u. Since u,b references same object b's color changes as well" u.myValue = "Yellow" u.speak()
b.speak()</lang>Output of the above program is as follows
creating initial objects of types S1, S2, and T S1 Meow Green S2 Woof Blue T Hello Purple Making copy of a as u, colors and types should match S1 Meow Green S1 Meow Green Assigning new color to u, A's color should be unchanged. S1 Meow Orange S1 Meow Green Assigning u to reference same object as b, colors and types should match S2 Woof Blue S2 Woof Blue Assigning new color to u. Since u,b references same object b's color changes as well S2 Woof Yellow S2 Woof Yellow
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.
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.
<lang python>import cPickle as pickle
source = {'a': [1, 2.0, 3, 4+6j],
'b': ('string', u'Unicode string'), 'c': None}
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. 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:
<lang python>target = source.__class__() # Create an object of the same type if hasattr(source, 'items') and callable(source.items):
for key,value in source.items: target[key] = value
elif hasattr(source, '__len__'):
target = source[:]
else: # Following is not recommended. (see below).
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).
Ruby
All Ruby objects inherit two methods for copying themselves: "clone" and "dup". I don't really understand the difference between them. <lang ruby>class T
def name "T" end
end
class S
def name "S" end
end
obj1 = T.new obj2 = S.new puts obj1.dup.name # prints "T" puts obj2.dup.name # prints "S"</lang>
Slate
All objects in Slate may be cloned unless they are clones of Oddball (like True, False, and Nil) 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 copy 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 (=) is overridden.
<lang slate>define: #T &parents: {Cloneable}.
define: #S &parents: {Cloneable}.
define: #obj1 -> T clone. define: #obj2 -> S clone.
obj1 printName. obj2 printName.</lang>
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:
<lang tcl>set varCopy $varOriginal</lang>
With objects, slightly more work is required because they are normally passed around by name/reference.
or
<lang tcl>oo::class create CanClone {
method clone {{name {}}} { # Make a bare, optionally named, copy of the object set new [oo::copy [self] {*}[expr {$name eq "" ? {} : [list $name]}]]
# Reproduce the basic variable state of the object set newns [info object namespace $new] foreach v [info object vars [self]] { namespace upvar [namespace current] $v v1 namespace upvar $newns $v v2 if {[array exists v1]} { array set v2 [array get v1] } else { set v2 $v1 } } # Other object state is possible like open file handles. Cloning that is # properly left to subclasses, of course.
return $new }
}
- Now a demonstration
oo::class create Example {
superclass CanClone variable Count Name constructor {name} {set Name $name;set Count 0} method step {} {incr Count;return} method print {} {puts "this is $Name in [self], stepped $Count times"} method rename {newName} {set Name $newName}
} set obj1 [Example new "Abracadabra"] $obj1 step $obj1 step $obj1 print set obj2 [$obj1 clone] $obj2 step $obj2 print $obj2 rename "Hocus Pocus" $obj2 print $obj1 print</lang> Which produces this output (object names might vary if you run it):
this is Abracadabra in ::oo::Obj5, stepped 2 times this is Abracadabra in ::oo::Obj6, stepped 3 times this is Hocus Pocus in ::oo::Obj6, stepped 3 times this is Abracadabra in ::oo::Obj5, stepped 2 times