Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CLOS shallow copy

47 views
Skip to first unread message

rif

unread,
Jul 3, 2003, 5:46:14 PM7/3/03
to

I've just started using CLOS recently. I find that given an object of
class foo, I often want another object of class foo that is the same
except for a single-slot. Therefore, I'd like to be able to "shallow
copy" objects then modify the single-slot I need (by "shallow copy", I
mean that each slot-value of the old object should be eq to the
corresponding slot value in the new object). Right now, I'm just
listing all the fields in the new object, which is of course a
terrible answer, and won't extend to the general case when the object
to be copied could be of class foo or some more-specific subclass.
What am I missing?

Cheers,

rif

Barry Margolin

unread,
Jul 3, 2003, 5:58:22 PM7/3/03
to
In article <wj0d6gr...@five-percent-nation.mit.edu>,

Nothing. Since this tends to be very class- and application-specific, CLOS
doesn't provide a built-in copy mechanism.

You can use the MOP to enumerate all the slots, and then copy all but the
one you want to change.

--
Barry Margolin, barry.m...@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Christopher Browne

unread,
Jul 3, 2003, 6:52:31 PM7/3/03
to

.. That this may be the best answer available at this point.

You are being tempted to find a more general answer, and that is
probably a mistake at this point. At the point that you need some
other policy, _that_ copier may need a different policy.

Why not wait until you see _two_ instances of needing additional
copiers, and see if a better answer emerges _then_?

-> If you never get to that point, then putting effort into it now was
a waste of time.

-> If you pick a policy now, and get it wrong, then you'll have to
rework it later.

-> Only if you predict things _perfectly_ now will there be no wasted
effort.
--
(format nil "~S@~S" "cbbrowne" "ntlug.org")
http://cbbrowne.com/info/advocacy.html
"Every sufficiently unreadable programming language contains a
reimplementation of APL and/or INTERCAL." -- Greenspun's Eleventh
Rule of Programming

Kenny Tilton

unread,
Jul 3, 2003, 10:58:40 PM7/3/03
to

rif wrote:
> I've just started using CLOS recently. I find that given an object of
> class foo, I often want another object of class foo that is the same
> except for a single-slot.

sounds like this is your problem. i cannot conceive such a thing. what
on earth are you doing?! :)

> Therefore, I'd like to be able to "shallow
> copy" objects then modify the single-slot I need (by "shallow copy", I
> mean that each slot-value of the old object should be eq to the
> corresponding slot value in the new object). Right now, I'm just
> listing all the fields in the new object,

you did not mention which CL you are using. try apropos on 'slots to see
if there is a function which will return all the slots of a class. even
a mop-weak mcl offers such a thing.

--

kenny tilton
clinisys, inc
http://www.tilton-technology.com/
---------------------------------------------------------------
"Everything is a cell." -- Alan Kay

Pascal Costanza

unread,
Jul 4, 2003, 6:13:30 AM7/4/03
to
Barry Margolin wrote:

> You can use the MOP to enumerate all the slots, and then copy all but the
> one you want to change.

Something like this should do the job.


(defmethod copy-instance (object)
(let ((copy (allocate-instance (class-of object))))
(loop for slot in (class-slots (class-of object))
do (setf (slot-value copy (slot-definition-name slot))
(slot-value object (slot-definition-name slot))))
copy))


Pascal

--
Pascal Costanza University of Bonn
mailto:cost...@web.de Institute of Computer Science III
http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

rif

unread,
Jul 4, 2003, 9:18:31 AM7/4/03
to

Kenny Tilton <kti...@nyc.rr.com> writes:

> rif wrote:
> > I've just started using CLOS recently. I find that given an object of
> > class foo, I often want another object of class foo that is the same
> > except for a single-slot.
>
> sounds like this is your problem. i cannot conceive such a thing. what
> on earth are you doing?! :)
>

Hmmm. Maybe. I'm definitely a newbie to CLOS, but this seems pretty
natural to me. In C++ at least, copying objects is not all that rare
--- is there a reason that it should be much rarer in CL?

rif

Frode Vatvedt Fjeld

unread,
Jul 4, 2003, 9:47:24 AM7/4/03
to
rif <r...@mit.edu> writes:

> Hmmm. Maybe. I'm definitely a newbie to CLOS, but this seems
> pretty natural to me. In C++ at least, copying objects is not all
> that rare --- is there a reason that it should be much rarer in CL?

CL has garbage collection, so there is no need to copy objects as part
of some object ownership protocol.

--
Frode Vatvedt Fjeld

Kenny Tilton

unread,
Jul 4, 2003, 9:52:37 AM7/4/03
to

The reason for the smiley in my original expression of astonishment is
that, not knowing the algorithm/functionality you are after, I really am
in no position to question your decision to implement it by copying.

ie, when I ended with "What on earth are you doing?!", I really wanted
to know. That said...

No, I do not think CL and C++ should differ in this regard; I would have
the same question about the C++ code.

Well, hang on. CLOS has :initform and :default-initargs options so newly
formed instances can be fleshed out if you will absent the
initialize-instance "constructor". And i-i lets one decide ad hoc which
of those to override, so one is not forever concocting new constructors.
If you are copying instances as a way of making new instances from
(effectively) prototype instances, CLOS /might/ offer alternatives.
Can't say too much in the abstract.

Greg Menke

unread,
Jul 4, 2003, 10:43:52 AM7/4/03
to

rif <r...@mit.edu> writes:

I think its rarer because it doesn't need to be done as often... heh..
More seriously though, I think the basic doctrine is that copy, like
comparison, on a complex object like an instance of a class is not
well defined. Sometimes a member-wise duplication or comparison is
enough to create a copy or test for equality/equivalence- and C++
gives you that, but sometimes its not appropriate. I think the idea
is to define comparison and copying operations yourself so they are
suitable for your application. I don't think you'll be stuck
hardcoding all the member manipulations as I imagine you can iterate
over class slots quite easily- I have to try that sort of thing one of
these days...

Gregm

Christopher Browne

unread,
Jul 4, 2003, 12:28:52 PM7/4/03
to
Martha Stewart called it a Good Thing when Greg Menke

<gregm...@toadmail.com> wrote:
> I think its rarer because it doesn't need to be done as often... heh..
> More seriously though, I think the basic doctrine is that copy, like
> comparison, on a complex object like an instance of a class is not
> well defined. Sometimes a member-wise duplication or comparison is
> enough to create a copy or test for equality/equivalence- and C++
> gives you that, but sometimes its not appropriate. I think the idea
> is to define comparison and copying operations yourself so they are
> suitable for your application. I don't think you'll be stuck
> hardcoding all the member manipulations as I imagine you can iterate
> over class slots quite easily- I have to try that sort of thing one of
> these days...

I recently acquired a set of Franz ACL manuals (they were being cast
off at U. of Waterloo), and saw what struck me as the Very Best
explanation of why "copy" is troublesome. The discussion usually
heads into abstruse issues of whether a particular slot should be
copied or reference. But Franz came up with a more concrete
example...

Suppose a particular object contains, as one of its attributes,
information about a network connection.

How then shall you "copy" the object?

-> Can you simply copy the data, and have the new object instance
throw data at the same network connection?

This might work, but it might not. If the "connection information"
is simply a socket ID, then throwing data at the connection may
*break* the connection.

-> Or perhaps you'll need to request a new network connection for
the new instance?

This may require addressing and authentication information that
wasn't even stored by the object.

These aren't "LISP" issues; they are universal, particularly in these
days of heavy use of networking.
--
(format nil "~S@~S" "aa454" "freenet.carleton.ca")
http://cbbrowne.com/info/wp.html
PALM BEACH COUNTY: We put the "duh" in Florida.

Kaz Kylheku

unread,
Jul 4, 2003, 12:51:49 PM7/4/03
to
rif <r...@mit.edu> wrote in message news:<wj0u1a2...@five-percent-nation.mit.edu>...

In well-written C++ programs, it's almost nonexistent. The objects
that are often copied in C++ are memory-management pseudo-objects, not
real abstractions that actually pertain to the application domain. In
other words, objects that make up for the lack of automated memory
management in the language.

Example: to pass and return a string to a function in C++, you end up
copying objects of type std::string. That class is a complex wrapper
that manages the actual string object using reference counting
techniques or whatever. When similarly manipulating strings in Lisp, a
simple reference is passed and returned, typically implemented as a
single machine word. The word is copied and propagated through the
machine as a simple bit-pattern, without any special code having to be
invoked. You don't need to wrap the pointer in an object, because the
management is in the language!

I can't remember that last time I copied a C++ class object which
wasn't some kind of resource manager, smart pointer or otherwise,
containing a pointer to the implementation of a real object, or which
wasn't just a plain struct containing simple data.

It's sometimes useful to copy simple data structures that just act as
containers of named properties. Lisp has structs, and it generates
copy functions for them. If you use DEFSTRUCT to define a struct
called FOO, you get a MAKE-FOO and a COPY-FOO function (by default).

Note that it's rarely correct to copy complex C++ objects using the
compiler-generated copy constructor or assignment operator. These
default behaviors lead to software defects. A couple of times in the
past I was burned because I accidentally copied a C++ object, and the
copy did not work properly. For instance I wrote something like:

MyClass obj = GetObj(); // GetObj returns reference

which was a simple typo for:

MyClass &obj = GetObj(); // Capture reference, don't copy!

A good, widely-known class coding recommendation for C++ is to do
this:

class MyClass {
private:
MyClass(const MyClass &);
void operator = (const MyClass &);
...
};

That is, make the copy constructor and assignment operator private,
and don't implement them. If anyone accidentally copies the object, a
diagnostic results, reminding them that the class doesn't support
copying unless someone is willing to put in the effort to do it right.

When you do implement these operators, you still face the
language-level stupidity that you have to choose one set of semantics
from among all of the possibilities and say ``this way of copying is
the most prominent, so it gets to use the language-level operators''.

Steven M. Haflich

unread,
Jul 6, 2003, 11:46:05 PM7/6/03
to
Pascal Costanza wrote:

> (defmethod copy-instance (object)
> (let ((copy (allocate-instance (class-of object))))
> (loop for slot in (class-slots (class-of object))
> do (setf (slot-value copy (slot-definition-name slot))
> (slot-value object (slot-definition-name slot))))
> copy))

I think not. (Not always. :-)

Assuming as you do that the implementation provides the MOP,
slot-value is defined to use slot-value-using-class, and for
spcialized metaclasses, neither slot-value-using-class nor
(setf slot-value-using-class) are required to do what they do
with standard-object. In particular, a specialized metaclass
might explicitly implement a method on either of these gf's
that signals error for certain slots. This is one way to
enforce a slot being read only (although there usually are
ways to violate such mechanisms, lisp being what it is).

Steven E. Harris

unread,
Jul 7, 2003, 3:04:45 PM7/7/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> A good, widely-known class coding recommendation for C++ is to do
> this:
>
> class MyClass {
> private:
> MyClass(const MyClass &);
> void operator = (const MyClass &);
> ...
> };
>
> That is, make the copy constructor and assignment operator private,
> and don't implement them.

That's wrapped up nicely in boost::noncopyable.น You can reduce your
declaration above to

class MyClass : noncopyable
{ /* ... */ };

assuming proper include and using directives or declarations are in
effect.


Footnotes:
http://www.boost.org/libs/utility/utility.htm#Class_noncopyable
http://www.boost.org/boost/noncopyable.hpp

--
Steven E. Harris :: seha...@raytheon.com
Raytheon :: http://www.raytheon.com

Will Hartung

unread,
Jul 7, 2003, 6:35:34 PM7/7/03
to

"Steven M. Haflich" <smh_no_s...@alum.mit.edu> wrote in message
news:3F08ED0C...@alum.mit.edu...

However, since the poster is new to CLOS, odds are pretty high that he's not
using a specialized metaclass. Odds are also, as mentioned elsewhere, that
this most basic MOP behavior is in most of the Lisps that folks,
particularly those new to the language, will use. So, this sounds like it
will do almost exactly what he asked for.

Now whether or not a "generic shallow copy" is a good idea isn't really
relevant. It's not our application, we're not coding it, and we don't have
the users history to really question his decision.

Help the new folks by enabling them to advance at their own rate using their
own techniques rather than pouring on the minutae that continues to confuse
and bewilder folks.

Regards,

Will Hartung
(wi...@msoft.com)

0 new messages