flan@cics.wustl.EDU (Ian Flanigan) (12/08/90)
I've run into a big, big snag using AKCL 1.492. I think it's a general problem with Common Lisp, but here goes: In my program I define a structure with defstruct: (defstruct hexboard (board (make-array (list x-board-dimension y-board-dimension) :element-type 'character :initial-element #\Space)) (ownership-list (make-array number-of-playersi :element-type 'list :initial-element NIL)) (connection-list (make-array (list x-board-dimension y-board-dimension) :element-type 'list :initial-element NIL)) ) Then I create an instance of the structure with: > (setq x (make-hexboard)) Now I try to make a copy of that structure: > (setq y (copy-hexboard x)) And change a few things: > (setf (aref (hexboard-board y) 0 0) #\X) Now I try to see what y is: > y #S(HEXBOARD BOARD #2A((#\X #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space)) OWNERSHIP-LIST #(NIL NIL) CONNECTION-LIST #2A((NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL))) Now I see what x is: > x #S(HEXBOARD BOARD #2A((#\X #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space) (#\Space #\Space #\Space #\Space #\Space #\Space)) OWNERSHIP-LIST #(NIL NIL) CONNECTION-LIST #2A((NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL) (NIL NIL NIL NIL NIL NIL))) How can I get it so that there are no side affects? I've tried copy-tree, but that doesn't work. I can't think of anything else to do. Any help would be greatly appreciated. Thanks. -- Ian Flanigan flan@cics.wustl.edu "You can never have too many napkins." wucs1.wustl.edu!cics!flan@uucp
barmar@think.com (Barry Margolin) (12/09/90)
Ian Flanigan complained that when he copies a structure whose slots contain arrays, and then modifies one of the arrays, the array in the other structure is also modified. Structure copiers are only supposed to copy the structure itself, not the objects referenced by the structure. They are like COPY-LIST rather than COPY-TREE. If you want more, you have to write your own copier function that does precisely what you want. There's no standard function that's able to read the programmer's mind and determine which parts of a structure should be copied and which should just be referenced. Such a function is not too hard to write. Given something like: (defstruct my-structure (slot1 (make-array ...)) (slot2 (make-array ...)) (slot3 (make-array ...))) (defun copy-my-structure-and-contents (my-s) (let ((old1 (my-structure-slot1 my-s)) (old2 (my-structure-slot2 my-s)) (old3 (my-structure-slot3 my-s))) (make-my-structure :slot1 (make-array (array-dimensions old1) :element-type (array-element-type old1) :initial-elements old1) :slot2 (make-array (array-dimensions old2) :element-type (array-element-type old2) :initial-elements old2) :slot3 (make-array (array-dimensions old3) :element-type (array-element-type old3) :initial-elements old3)))) Note that this still only copies one level more than the automatically-generated copier. If you also want to copy the objects referenced in the arrays you'll have to do more. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
srt@aerospace.aero.org (Scott "TCB" Turner) (12/11/90)
Barry writes: >Note that this [structure copier] still only copies one level more >than the automatically-generated copier. If you also want to copy >the objects referenced in the arrays you'll have to do more. One of the better arguments for object-oriented programming. -- Scott Turner
jgk@osc.COM (Joe Keane) (12/14/90)
In article <1990Dec8.180825.21702@Think.COM> barmar@think.com (Barry Margolin) writes: >Structure copiers are only supposed to copy the structure itself, not the >objects referenced by the structure. They are like COPY-LIST rather than >COPY-TREE. If you want more, you have to write your own copier function >that does precisely what you want. There's no standard function that's >able to read the programmer's mind and determine which parts of a structure >should be copied and which should just be referenced. >Note that this [structure copier] still only copies one level more >than the automatically-generated copier. If you also want to copy >the objects referenced in the arrays you'll have to do more. In article <93985@aerospace.AERO.ORG> srt@aerospace.aero.org (Scott "TCB" Turner) writes: >One of the better arguments for object-oriented programming. I don't see what object-oriented programming has to do with this. The same problems with deep vs. shallow copying come up, and there's no magic solution which always does what you want. One thing i do know is that it's a hell of a lot easier to automatically generate functions you want in Lisp than in C++.
srt@aerospace.aero.org (Scott "TCB" Turner) (12/15/90)
Joe Keane writes: >In article <93985@aerospace.AERO.ORG> srt@aerospace.aero.org (Scott "TCB" >Turner) writes (about structure copying): >>One of the better arguments for object-oriented programming. > >I don't see what object-oriented programming has to do with this. The same >problems with deep vs. shallow copying come up, and there's no magic solution >which always does what you want. Imagine trying to write a "copy" function in generic Lisp that will take any type of object and provide an unlimited depth copy of that object. You do something along these lines: (defun copy (foo) (cond ((type-1 foo) (apply #'create-new-type-1-w-elements (mapc #'copy (destructure-type-1 foo)))) ((type-2 foo) ...))) For each type that you know about, you destructure it, copy all the elements and then put it back together into a new gestalt. Problem is, this requires that you know how to destructure and create each possible type that will ever exist in your system. Difficult. In object-oriented programming, each type simply has an operation "copy" that knows how to destructure and create that type and "voila!" the problem is solved. The same information and problems exist in either case. OOP is not a panacea, no matter what certain C++ cultists seem to think. But OOP does make this problem more tractable (and expandable) but organizing the information wisely. -- Scott Turner