Monday, June 30, 2008

Singleton Methods

Ruby has a neat feature called Singleton Methods. The idea behind them is that you can define a method on an instance of an object, and that method only exists for that instance. Sounds pretty crazy the first time you learn about it, but it can prove quite powerful. This feature only makes sense in conjunction with duck typing (which I would like to dedicate another post about at some point). Don't expect a JSR for Singleton Methods for Java any time soon! Actually, you can do something similar using an anonymous class, but it would be rather hard to invoke, and you would have to define the method at the point of creation.

How could Singleton Methods possibly be useful? Well, my personal favorite is for unit tests. I prefer testing with actual classes, but sometimes that is not feasible. The object in question may not be built yet. It may be a legacy object that you don't want to touch because there aren't all that many tests for it, and it would just be easier to pretend that you have an instance of it. Perhaps the most likely scenario is that you are using a framework, and it is just plain annoying or infeasible to construct the real version of the object in question. Sockets are a prime candidate for this exact situation. Whatever the reason, you want to mock an object. What do you do in Java? You either construct an anonymous class, or you define a mock class which extends the object in question (or implements the required interface), and voila!

Except... anonymous classes are rather cumbersome, and an actual mock class separates your mock logic with the test that requires it. You could of course have a general purpose mock that is used everywhere, but you will have to go back and forth between the mock definition and your test class definition whenever you are developing tests that use the mock.

In comes Singleton Methods to the rescue! Your method only connects, and then does some extra work once it is connected, so you just need to mock the connect method. The following code would accomplish this goal:

mock = Object.new
def mock.connect()
end
invoke_my_method_with mock
# assert some conditions

Then, you should have a test in case the connect fails, right? Your object needs to do some other logic when the connection doesn't actually connect! So, the next test mocks the object differently:

mock = Object.new
def mock.connect()
raise "Some exception"
end
invoke_my_method_with mock
# assert some other conditions

Because of duck typing, your method doesn't know that it didn't get an actual Socket, but you were able to keep the mock logic near the test logic (in a clean and concise manner), which makes it a lot clearer what the test is testing.

Making mocking easier is nice, but ever since I learned Singleton Methods, I have been itching to use it in another way. Let's say we have an entity in our system that has a set of actions possible. My favorite case is a character in a game. There are many possible actions, but our character is only able to use a few of these actions. He can kick, but he can't punch. Each command could be a different Singleton Method! Now, whenever the character wants to punch, just invoke punch with the actual character instance. Of course, this means you have to be prepared that the character can't ACTUALLY punch, so you must catch a method missing error and inform the character that it tried to do an action it didn't know how to do (or perhaps didn't even exist). I don't know how this type of design would actually pan out, but it sure seems like the perfect fit for the feature.

I bet there are other good uses for Singleton Methods, so don't let these ideas limit the possibilities!

No comments: