Polymorphic copy: Difference between revisions

Content added Content deleted
No edit summary
(Add Racket Task)
Line 1,297: Line 1,297:


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).

=={{header|Racket}}==
===Using prebab-structures===
Only prefab-structures can be copied on the fly. It’s possible to copy other structure using generics or structure-type-properties to implement a “magic” method.
<lang Racket>#lang racket/base

(define (copy-prefab-struct str)
(apply make-prefab-struct (vector->list (struct->vector str))))

(struct point (x y) #:prefab)
(struct point/color point (color) #:prefab)


(let* ([original (point 0 0)]
[copied (copy-prefab-struct original)])
(displayln copied)
(displayln (eq? original copied)))

(let* ([original (point/color 0 0 'black)]
[copied (copy-prefab-struct original)])
(displayln copied)
(displayln (eq? original copied)))</lang>
{{out}}
<pre>#s(struct:point 0 0)
#f
#s(struct:point/color 0 0 black)
#f
</pre>

===Using classes===
There is no build-in clone method, so the class (or the interface) must implement it.
<lang Racket>;#lang racket

(define point%
(class object%
(super-new)
(init-field x y)
(define/public (clone) (new this% [x x] [y y]))
(define/public (to-list) (list this% x y))))

(define point/color%
(class point%
(super-new)
(init-field color)
(define/override (clone) (new this% [x (get-field x this)] [y (get-field y this)] [color color]))
(define/override (to-list) (list this% (get-field x this) (get-field y this) color))))
</lang>
{{out}}
<pre>(#<class:point%> 0 0)
#f
(#<class:point/color%> 0 0 black)
#f</pre>


=={{header|Ruby}}==
=={{header|Ruby}}==