I love Smalltalk. Have for a long time. Among the things I've come to love about it over the years, is as a model, which encourages binding behavior to data (state). This is a focus of problem solving in computer programming, that works well for many domains. In a universe far far away, where people don't like state, they do the functional thing and avoid it (state).
In the Smalltalk universe, we don't spend too much time thinking about stateless functions. We're usually in a search for what data, a given behavior belongs to. What is the right receiver? Whose responsibility is this? Like all simulations, this breaks down some times. There are the rare occasions where we make "utility methods". These are methods that can live anywhere. The only state they need is local state (temps and arguments). The reasons for making them are varied, but for whatever reasons, it happens sometimes. It's not always a perfect world.
Sometimes, if we get enough of these utility functions, we place them on a Class. Maybe there's a logical class that they're related to, maybe we make a new class, to act as a gathering point for these functions. One example of this, in the VisualWorks system, is the SystemUtils class. It's not the greatest example. A healthy percentage of its behavior should probably be moved to the state it truly goes with. But even after carving that all away, we end up with a chunk of utilities that have some value.
This same approach has affected, over the years, the way I do ExternalInterface subclasses. When I make one, I'm usually creating a flat facade to a reentrant (read: necessarily stateless) C library. The C functions operate on the data I pass to them. Since they're justifiably just utility methods, I treat them the same way as SystemUtils. I put the methods on the class side. Getting to that point, is a history of asking myself "why?" and getting past common idioms/patterns that we like to generally embrace.
If one doesn't follow this pattern, one has to create an instance of the utility method holder. Code like this:
LibCairo new cairo_clip: handle.
At one point, I found myself asking "why do I do this?" Of course, there are the standard answers such as "class behavior outside of instance creation/constants is bad." But at some point, I got past that. I found myself asking "what am I gaining by creating a new instance each and every single time, other than needlessly exercising the allocator/collector and proving I like to type 'new'?" "What makes these never ending stream of new entities differ, one from another?"
Flummoxed with this situation, I began doing the "cached singleton" thing. You know the drill. Add a class instance variable called default or current. Add an accessor for it; said accessor lazy initializes the variable to the new instance. Now I'm not making an endless stream of objects, all of which differ from each other in no meaningful way, and all which just turn around and die. Now I would write code that looks like:
LibCairo current cairo_clip: handle.
There's an amusing irony to me with this one. I now type more than I used to type ('current' vs just 'new'). And the coolest thing, is that I managed to add state to the equation. It was until then just a big bag of utility functions. But now, by creating a slot to store the singleton instance, and the code to manage it, I've managed to introduce state into the problem. It's almost like, I've done extra work, just to get state into the problem, so I can feel comfortable in my Smalltalk universe where state is so important.
This led to further application of the "why do I do this?" scalpel. Once I realize that I created an artificial/arbitrary/extra amount of state to manage, I realize that classes are objects too. And I've already got a singleton managed instance of that. Why do this caching, when I could just put the methods right there, just as well? Which brings us around to the following present day application:
LibCairo cairo_clip: handle.
It's just a utility method. I type less this way. I write less code to intialize/access singletons this way. And I haven't figured out what I lose yet.
I just finished up converting the last ExternalInterface in CairoGraphics to follow this pattern. I removed an instance variable. Methods which set it. I was able to remove comments describing how they were managed. The code reads more direct now. This is my story of why I do ExternalInterfaces the way I do.