From: John Prevost <j.prevost@cs.cmu.edu>
To: Alessandro Baretta <alex@baretta.com>
Cc: John Prevost <j.prevost@cs.cmu.edu>,
zze-MARCHEGAY Michael stagiaire FTRD/DTL/LAN
<michael.marchegay@rd.francetelecom.com>,
Ocaml <caml-list@inria.fr>
Subject: Re: [Caml-list] Deep copy
Date: 16 Jul 2002 04:19:50 -0400 (34.711 UMT) [thread overview]
Message-ID: <86it3grsnt.fsf@laurelin.dementia.org> (raw)
In-Reply-To: <3D3354C0.9040403@baretta.com>
>>>>> "ab" == Alessandro Baretta <alex@baretta.com> writes:
{... asked about deep copy ...}
In any case, here's a simple example of the appropriate way to
implement deep copy:
(* just for reference *)
class type deep_copyable =
object ('s)
method deep_copy : 's
end
class point =
object
val mutable x = 0
val mutable y = 0
method get_x = x
method get_y = y
method set_x x' = x <- x'
method set_y y' = y <- y'
method deep_copy = {< >} (* no mutable slots *)
end
class rect =
object
val mutable ul = new point
val mutable lr = new point
method get_ul = ul
method get_lr = lr
method set_ul ul' = ul <- ul'
method set_lr lr' = lr <- lr'
method deep_copy = {< ul = ul #deep_copy; lr = lr #deep_copy >}
end
Note that this strategy works even if class rect doesn't have mutable
slots--since it uses the special cloning with override construct.
There is some awkwardness with inheritance in that an inheriting class
really needs to have mutable values to work well. You either have to
do:
class tri =
object
inherit rect as super_r
val mutable ur = new point
method get_ur = ur
method set_ur ur' = ur <- ur'
method deep_copy =
let c = super_r #deep_copy in begin
c #set_ur (ur #deep_copy);
c
end
end
(* or *)
class alt_tri =
object
inherit rect
val mutable ur = new point
method get_ur = ur
method set_ur ur' = ur <- ur'
method deep_copy =
{< ul = ul #deep_copy; lr = lr #deep_copy; ur = ur #deep_copy >}
end
The first version has a problem if ur does not have a public "set_"
method--since the copy is a different object, you cannot manipulate
its slots directly. The good thing about it is that it doesn't need
to list all of the inherited slots directly, since the inherited
deep_copy method takes care of that. This problem will show up if you
want to copy a field which is private state (not settable from
outside.)
The second version must list all of the slots to copy directly. It
doesn't require that the slot to be modified has a public set method.
But: if the superclass changes to have more slots that must be
duplicated, the subclass must also change. If it does not, the
internal invariants of the class inherited from may fail, since two
objects now share a resource.
A final version uses composition instead of inheritance (which can
often be a good thing) to handle this:
class comp_tri =
object
val comp_r = new rect
val mutable ur = new point
method get_ul = comp_r #get_ul
method set_ul = comp_r #set_ul
method get_lr = comp_r #get_lr
method set_lr = comp_r #set_lr
method get_ur = ur
method set_ur ur' = ur <- ur'
method deep_copy = {< comp_r = comp_r #deep_copy; ur = ur #deep_copy >}
end
The composition version requires that each method you want to
replicate be replicated by hand. The drawback is that if the
contained class which you're delegating for changes, you may not have
all the methods which the composed class has. The good thing about
this approach is that if this causes real problems, the type system
should pick up on it. (i.e. calls to those methods on your class will
fail.) And--there is no chance that the internal invariants of the
composed class will be broken: you use only the published interface to
interact with it. The drawback is that you cannot override behavior
of the composed object's calls to itself.
In summary:
* The mechanism used in "tri" is the most common case when classes do
not have internal (hidden) state that must be duplicated. The
problem arises when the *inheriting class* has such state, not when
the *inherited* class has such state. It allows overriding of self
method calls.
* The mechanism used in "alt_tri" handles internal state in a way
which may break, but allows overriding of self method calls. The
breakage may be difficult to detect.
* The method used in comp_tri handles internal state in a safe
way--invariants are never broken--but does not allow overriding of
self method calls, since no subclassing is actually occuring. This
mechanism is most appropriate in cases where the interface is only
extended, and no old methods are to be overridden.
I hope this rundown is useful to you. Although copying of state is
particularly troublesome, these three patterns (call superclass do
extra work, replace superclass, composition) also arise in other sorts
of methods, with similar drawbacks and advantages. In the end, it all
comes down to the following observation: subclassing may lead to
useful sharing of behavior, but it breaks modularity--whenever a
superclass changes, all subclasses must be examined to be sure their
behavior remains correct.
John.
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
next prev parent reply other threads:[~2002-07-16 8:13 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-07-15 15:24 zze-MARCHEGAY Michael stagiaire FTRD/DTL/LAN
2002-07-15 15:24 ` Eray Ozkural
2002-07-15 18:18 ` Alessandro Baretta
2002-07-15 19:53 ` Alessandro Baretta
2002-07-15 22:35 ` John Prevost
2002-07-15 23:03 ` Alessandro Baretta
2002-07-16 8:19 ` John Prevost [this message]
-- strict thread matches above, loose matches on Subject: below --
2002-07-15 10:06 zze-MARCHEGAY Michael stagiaire FTRD/DTL/LAN
2002-07-15 13:42 ` Ken Wakita
2002-07-15 14:43 ` Eray Ozkural
2002-07-15 15:33 ` Ken Wakita
2002-07-15 23:09 ` Ken Wakita
2002-07-15 15:02 ` Eray Ozkural
2002-07-15 15:27 ` Nicolas Cannasse
2002-07-15 15:40 ` Eray Ozkural
2002-07-15 16:22 ` sebastien FURIC
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=86it3grsnt.fsf@laurelin.dementia.org \
--to=j.prevost@cs.cmu.edu \
--cc=alex@baretta.com \
--cc=caml-list@inria.fr \
--cc=michael.marchegay@rd.francetelecom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox