Extracted from ML discussion
Juan writes on the ML
Morphs should be copied using #copy.
David Lewis writes on the ML
I do not know the historical background, but Object>>clone invokes #primitiveClone
in the VM. This is an efficient shallow copy, in which the object header and data
fields are copied to a newly allocated object, and the object hash and GC bits
are updated in the new copy.
Ken Dickey writes
The original Object>>copy would work where I implement postCopy to set location to a new MorphicTranslation.
Object>>copy
^self shallowCopy postCopy
Juan writes
I searched a bit more and found http://lists.squeakfoundation.org/pipermail/vm-dev/2014-February/014683.html and the more detailed http://lists.gforge.inria.fr/pipermail/pharo-project/2010-January/019801.html (by Levente).
After these references, I decided to remove #clone from Cuis. Most senders were replaced by sends to #shallowCopy (it uses the same VM primitive). But for several, calling #copy works the same, and #copy sounds more natural to me. I also refactored several implementations of #copy et al, in SequenceableCollection and AbstractSound hierarchies. Will commit to github soon.
I think that this must have been done for efficiency, to provide the fastest
possible means of shallow copying an object. The methods in the VM and in Object
are both old enough that they had no author initials, so this was a very early
optimization in Squeak.
David T. Lewis writes
Object>>clone can be replaced by #shallowCopy. Perhaps it is time to
deprecate #clone.
Juan is removing it from Cuis, with reference to this summary by Levente:
http://lists.gforge.inria.fr/pipermail/pharo-project/2010-January/019801.html
Juan writes
My point is that usually we don't really need closures:
a) For control flow, all we need is code blocks. The compiler knows that, and optimizes most cases, avoiding the creation of a real closure. These are never serialized by themselves (maybe the complete method is serialized).
b) Real closures. Used for new control structures, that the compiler doesn't know about. Also used for functional programming and continuations. Not really needed most of the time: Squeak existed without closures for over 10 years. These are hard and expensive to serialize.
c) "context free lambdas" a.k.a. "clean closures". State is stored in objects. All state is passed to the block as arguments. These are easy and cheap to serialize. A typical example for these is a sort block in a SortedCollection.
The code you sent me uses b). It stores state in variables in the context of the closure. But this is not really needed. I could convert your code to c). See the attach. What I did is to take that state and store it in an instance variable. There was yet another variable that could simply be a temporal inside the block. Then, the default implementation of Morph>>copy worked without problems.
I think it would be good to have different syntax for "clean" or "context free" blocks. And encourage their use above real closures, whenever possible.
Well, but Morph is the same as your automobile. Copying a morph (usually) means copying submorphs. But not owner (otherwise, the whole World gets copied). This is taken care at Morph >> storeDataOn: I know this is rather hidden, code is not really clear, and maybe some framework to handle "creation relations" would be in order.
The shallowCopy postCopy approach works only for objects that don't form graphs. For these, the issues of duplications appears. The old #veryDeepCopy from ST-80 was complicated, and it had problems. I claim:
-
appropriate semantics for copying is usually a matter for each object to define. That's why it is ok to copy the #copy method from Object to your morph if appropriate.
-
The problems of duplication, identity, etc, are the same for copy as for serialization. That's why it is ok to use a serializer to copy graph objects.
So, I recommend (as general advice) to use clean closures if at all possible (as I said in the other thread), and to use the serializer to copy objects that form graph structures (like morphs). But, as #copy semantics is a responsibility for each object to provide, if this general advice is not applicable, instead of calling #shallowCopy, or creating new copy messages, I recommend implementing #copy appropriately for each class.
I hope all this makes sense for you.
Ken Dickey writes
Very good sense, but for #clean I would substitute the term #trivial, which makes more sense in this context.
After all, closures are called closures because they "close over their environment".
Trivial closures are more akin to Traits. We could split closures, including nested closures, into trivial code blocks and their associated environment vectors.
The basics are covered in:
http://www.iro.umontreal.ca/~feeley/papers/FeeleyLapalmeCL92.pdf