This post is part of an ongoing series about Affordances and Programming Languages.

While developing DoubleAgents in Smalltalk, I wanted to have a way to make an “in-place” test double. That is, to stub or mock a method on an existing instance or class while leaving the rest of the object intact. In order to accomplish this goal, I needed a way to define a method on a single instance, rather than on a class where it would affect all of the other instances of the class as well.

Ruby makes this very easy, because each object has an eigenclass (also known as a singleton class) in addition to its more traditional class. So, to define a per-instance method:

Per-Instance Method in Ruby
# Assume a class Foo has been defined
foo = Foo.new
def foo.per_instance_method
# ...
end

Smalltalk doesn’t have eigenclasses for instances, so requires more magic:

Per-Instance Method in Smalltalk
"Assume a class Foo has been defined"
foo := Foo new.
foo changeClassTo: foo class copy.
methodText := 'perInstanceMethod
"code goes here"
'.
methodNode := foo class compilerClass new
compile: methodText
in: foo class
notifying: nil
ifFail: [].
foo class replaceMethodAt: #perInstanceMethod withMethod: methodNode generate.

Some of the extra verbosity here is to keep the per-instance method from showing up in the development tools, or causing any packages to be marked as modified. For my purposes, this is what I needed, since the per-instance method only lives for the duration of the current test case.

The main trick here is to make a copy of the object’s class and then change the class of the object to the copy. Another option is to make a new subclass of the object’s class and then change the class.

As you can see, Ruby’s object model provides affordances for this kind of meta-programming, and Smalltalk does not. It’s still possible to make it work in Smalltalk, but it takes more magic and clever tricks.