duplicating morphs with custom behavior

Ward Cunningham ward at c2.com
Wed Nov 21 05:53:47 UTC 2001


I'm using morphs that can be customized per instance. I do this by creating a new instance of Behavior (a lightweight, anonymous Class) for each morph. This works great until I try to copy the morph which runs into this method in Object:

veryDeepCopyWith: deepCopier
 "Copy me and the entire tree of objects I point to.  An object in the tree twice is copied once, and both references point to him.  deepCopier holds a dictionary of objects we have seen.  Some classes refuse to be copied.  Some classes are picky about which fields get deep copied."
 | class index sub subAss new uc sup has mine |
 deepCopier references at: self ifPresent: [:newer | ^ newer].  "already did him"
 class _ self class.
 class isMeta ifTrue: [^ self].  "a class"
 new _ self clone.
 class isSystemDefined ifFalse: [
  uc _ deepCopier uniClasses at: class ifAbsent: [nil].
  uc ifNil: [deepCopier uniClasses at: class put: (uc _ self copyUniClassWith: deepCopier)].
  new _ uc new].  "**** trouble here *****"
 deepCopier references at: self put: new. "remember"
 (class isVariable and: [class isPointers]) ifTrue:
  [index _ self basicSize.
  [index > 0] whileTrue:
   [sub _ self basicAt: index.
   (subAss _ deepCopier references associationAt: sub ifAbsent: [nil])
    ifNil: [new basicAt: index put: (sub veryDeepCopyWith: deepCopier)]
    ifNotNil: [new basicAt: index put: subAss value].
   index _ index - 1]].
 "Ask each superclass if it wants to share (weak copy) any inst vars"
 new veryDeepInner: deepCopier.  "does super a lot"

 "other superclasses want all inst vars deep copied"
 sup _ class.  index _ class instSize.
 [has _ sup compiledMethodAt: #veryDeepInner: ifAbsent: [nil].
 mine _ sup instVarNames.
 has ifNotNil: [index _ index - mine size]
  ifNil: [1 to: mine size do: [:xx |
    sub _ self instVarAt: index.
    (subAss _ deepCopier references associationAt: sub ifAbsent: [nil])
      "use association, not value, so nil is an exceptional value"
     ifNil: [new instVarAt: index put:
        (sub veryDeepCopyWith: deepCopier)]
     ifNotNil: [new instVarAt: index put: subAss value].
    index _ index - 1]].
 (sup _ sup superclass) == nil] whileFalse.
 new rehash. "force Sets and Dictionaries to rehash"
 ^ new

This method is careful to check for one-off Behavior and kindly duplicates the non-system defined Behavior and calls it uc. Then it replaces the cloned copy of the object (in the temp new) with the statement:

    new _ uc new.

I've marked this statement with the comment, **** trouble here *****. And here is the trouble: The rest of the method assumes the temp new was created with the statement:

    new _ self clone.

This is much like a shallowCopy in that it copies instance variables over to the cloned object. But that isn't what "uc new" does. It creates an object with the newly copied behavior, but without all the instance variables copied forward. The net result is that my duplicated morph ends up empty.

So here is my question for the experts on this list: Did this code ever work? I'd never heard of a uniClass before reading this code. But near as I can tell it is something along the lines of my stuff. Is this a work in progress or a fundamental misunderstanding on my part?  Thanks for the help. -- Ward

--
Ward Cunningham
v 503-245-5633   mailto:ward at c2.com
f 503-246-5587   http://c2.com/






More information about the Squeak-dev mailing list