[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

the mysterious wake of copy-instance

i need to be able to make copies of view hierarchies (e.g., views inside of
views inside of views) whether on-screen or off.  it is fairly obvious that
macl's copy-instance cannot be directly applied, since it only changes the
top level pointers.  for example, if view a contained c and d

(setq b (copy-instance a))

would generate a "new" (and pretty much distinct) a, now called b. 
unfortunately, b's subviews would be the identical "c" and "d" of view a. 
even though "c" and "d" are listed as subviews of b (when you call
view-subviews...) it seems that you cannot? remove "c" and "d" from b (for
good reason, maybe) since they aren't really there to begin with. 
certainly, "c" and "d" can only have one view-container each -- and since
b's versions are "copies" of the a subviews, b's subviews should have
view-container a.

anyway, bad.

but, why is it incorrect to recursively do the following --
1) store the subviews of the to-be-copied view
2) remove the subviews
3) copy-instance the box (while it has no subviews -- so as to avoid the wrath 
   of the above
4) recursively call this method (1-5) on each of the subviews in the store (1)
5) add the subviews back on to the original box and add the individual
   from (4) to the new (copy-instanced) box.

anyway, implemented as follows:

(defmethod rec-copy-instance ((view view))
   (let ((new-view nil)
           (subview-list nil))
      (do-subviews (subview view)
         (setq subview-list (cons subview subview-list))        ;; step 1
         (remove-subviews view subview))                        ;; step 2
      (setq new-view (copy-instance view))                      ;; step 3
      (dolist (subview subview-list)
         (add-subviews new-view (rec-copy-instance subview))    ;; 4 & 5, p 2
         (add-subviews view subview))                           ;; 5, part 1

yields the result:

?(setq a (make-instance 'view))
 (setq b (make-instance 'view))
 (setq c (make-instance 'view))
 (setq d (make-instance 'view))
#<VIEW #xBF7571>
#<VIEW #xBF7629>
#<VIEW #xBF76E1>
#<VIEW #xBF7799>

?(add-subviews a c d)

?(subviews a)
(#<VIEW #xBF76E1> #<VIEW #xBF7799>)

?(setq b (rec-copy-instance a))
#<VIEW #xBF7FC1>

?(subviews b)
(#<VIEW #xBF8001> #<VIEW #xBF7799> #<VIEW #xBF8041> #<VIEW #xBF76E1>)

?(subviews a)
(#<VIEW #xBF8001> #<VIEW #xBF7799> #<VIEW #xBF8041> #<VIEW #xBF76E1>)

now a b and are not equal to each other in any way, though their subviews
are "equal."

both of which contain c and d (as the second and fourth elements,
respectively) as well as two other elements which are their copies.  why
are the two identical? is the algorithm faulty? its implementation? or my
understanding of the way in which copy-instance works.  is this just the
way copy-instance works (to avoid the difficulty in paragraph 1) -- though
if this is true, it doesn't work very well, because it's easy enough to
instantaneously crash a mac, from the lowliest to the most powerful, doing
this kind of thing.

is this a handle problem?  am i maybe just copying the handle (in which
case both are still pointing to the same thing)?

the point is -- how should i achieve this copy.  i COULD do a brute force,
recursive slot-by-slot copy, changing the appropriate slots, but this would
be tedious and drawn-out, because i'm actually copying various
specializations of view, several of which have additional slots.  i would
like to avoid this.

thanks for your input,

chris crone
school of education and social policy,
institute for the learning sciences
northwestern university