In the IRC channel today I brought up the topic of
changeClassTo:. I actually had a legitimate use for it for a change
and I'd forgotten the exact name of the selector. Naturally, I
found it 2 seconds after I asked for people to jog my memory.
Smalltalk makes finding selectors very easy.
But, as these things happen, Anthony Lander suggested that I may
in fact want to use changeClassToThatOf: instead of changeClassTo:.
In his opinion, changeClassTo: was bad to use because you could
give it an argument that wasn't a class and therefore crash the
VM.
The idea being that changeClassToThatOf: takes an instance and
sets your instance to have the same class as the argument. All well
and good, but Rado piped in saying he didn't buy the argument. In
my case, the code would require that I instantiate an instance of
my class just to call the supposedly 'safe' method.
The battle raged and now I present to you the evidence for my
side of the argument. Here, take a look at the two methods:
changeClassTo: aClass
aClass adoptInstance: self.
^self
And:
changeClassToThatOf: anObject
"Change the class of the receiver to the class of anObject. Fail if either the
receiver or anObject is immutable (which includes immediates),
or if none of the following cases holds:
1. The receiver and anObject are both byte-type.
2. The receiver is any pointer-type object, anObject is a
non-indexable pointer-type object, and the storage sizes (i.e. the
number of named instance variables plus the number of indexed
instance variables, if any) of the two objects are the same.
3. The receiver is any pointer-type object, anObject is an indexable
pointer-type object, and the storage size of the receiver is at least
as large as the number of named instance variables of anObject.
Compare with the adoptInstance: primitive."
535 errorCode: errCode>
^(errCode ~~ nil
and: [errCode name = #'no modification'])
ifTrue: [self noModificationErrorFor: #changeClassToThatOf: index: nil value: anObject]
ifFalse: [self primitiveFailed]
Now.. it seems quite clear to me which implementation is nicer. The changeClassToThatOf: calls a primitive - very unSmalltalky and the method itself is apparently not self explanatory enough, because the author included a gigantic comment. Conversely, the changeClassTo: is straight to the point, essentially one line of code.
And to put the final nail in the coffin, there is no safety issue calling changeClassTo: because it uses double dispatch, a very Smalltalky thing to do indeed. It defers the logic off to somebody who knows better by calling adoptInstance: on the class. If you give its something that isn't a class, naturally it will say, Sorry, I don't understand that.. and you can be on your merry way without having destroyed the VM.
So, in summation, I believe changeClassTo: is better than changeClassToThatOf: - but when it comes down to it, it depends on what kind of object you have at hand at the time you want to make the call. If you have an instance, use the latter, if you have the class, use the former.