Many object-oriented languages include a method for making a shallow copy
of an object. A shallow copy is made by copying the values of
instance variables. If the instance variables hold references to other
objects, only the references are copied, not the objects being referred
to. Thus if this shallow clone method (call it )is applied to the head of a linked list, only the head node is copied while
the rest of the list is shared between the new and old lists.
is often available as a method in all classes (e.g., it is
often provided by a
class, which is implicitly a superclass of all other
classes).
Often it is desirable to write a method which is based
on
. One typically first writes code to send the
message to self to make the shallow copy, and then code to
clone all objects held in the instance variables.
Suppose we have a class that includes a method
, which returns an object of type
.
See Figure 6. Suppose we now define a subclass
of
which includes new methods as well as a new instance variable holding
an object. Then
should be redefined to clone the contents of this new instance variable
after all of the code in the original
from
has been
executed.
Unfortunately, the rules of the simple type systems require that
for
to also return a
, just as in
, even though it is obvious that it actually returns an object
of type
. While this is not type-unsafe, it represents an
unnecessary loss of information in the type system. If we write
for
of type
, the
type checker will complain, even though the object resulting from
has a method
.
In these circumstances, Object Pascal, C++, and Java programmers
would normally be forced to perform a type cast to tell the compiler
that the cloned object has the type . In the case of
Object Pascal and C++, the type cast is unchecked. In Java, it would
be checked at run-time. Modula-3 programmers would use a typecase
statement which also performs a run-time check to get the same effect.
One could attempt working around these deficiencies in the static type
system by making up a new name for the revised
method (e.g.,
). Unfortunately this would mean that
inherited methods that included a message send of
would
call the old
for
rather than the updated
method from
actually desired. As a result the value in the new
instance variable will not be cloned, possibly causing problems later in
the program. Thus the restriction on changing types of methods in
subclasses gets in the way of the programmer, even though there should be
no real typing problem. Not surprisingly, we have similar problems
even writing down the type of the built-in
. In
Object Pascal,
is simply given a type indicating
that it returns an element of the
type. It must then be
cast to the appropriate type.