TITLE: Turning Up the Knob on Functional OOP and Imperative OOP AUTHOR: Eugene Wallingford DATE: January 27, 2011 4:48 PM DESC: ----- BODY: One of my students has been learning Haskell as a prelude to exploring purely functional data structures. Recently, he wrote a short blog entry describing some of the ideas he has found most exciting. It ended with a couple of code snippets showing the elegance and brevity of list comprehensions compared to what he was used to in imperative languages. The student apologized for his imperative example, because he wrote it in Java using objects. In his mind, that made it object-oriented, not imperative. This is a common misconception. Most OOP is imperative. Objects have state that changes. Of course, one can write object-oriented code in a functional style by emphasizing return values and by creating new objects instead of changing existing objects. Certain kinds of objects, such as money, should probably be implemented as value objects without modifiable state. But most OO practice and intent is stateful, hence imperative. I've read many a blog entry over the last few years in which OO gurus extol functional OO as a way to write better code. I think we can overdo it, though. Whenever I take this idea too far, though, I soon find myself contorting the code in a way that seems to serve the idea but not the program I am writing. Still, sometimes it can be fun to turn the knob on the functional OO dial up to 10 and try to write purely functional OO code, with no side effects of any sort. This kind of programming challenge has always appealed to me. It can teach you a lot about the strengths and limits of the tools you use. It occurs to me that one way to enforce the rules of the functional OO challenge would be to turn off the imperative features in my language. That can be tough to do in a language with libraries full of stateful objects. But simply turning off the assignment operator in a language such as Java would make many of us struggle to write even simple programs. Actually, I had the idea of turning off assignment statements late in a long conversation I had with myself while thinking about my student's comment and my response to him. If most OO is imperative, I wonder what it would be like to write "purely imperative" OO code. This would mean creating objects that never returned a value in response to a message. In a sense, these objects would be pure state and action, at least from the perspective of other objects in the system. At first, this idea seemed absurd. What value could come from it? This stylistic challenge is quite easy to enforce, either in practice or in tools: simply require all methods to be void. Voilé! No return statements are allowed. No values can be passed from one object to another in response to a message. An object would affect the state of the program either by modifying its own state or by sending a state-changing message to another object, perhaps an argument that it received along with a message. Talk about Tell, Don't Ask! In this style of programming, I can only tell objects to do things. I can't ask for any data in return. So, perhaps some value could come from this little challenge after all. I would have to take Tell, Don't Ask -- and encapsulation -- seriously. Programming in this way can help us see just how much we can accomplish with truly independent objects, providers of services who encapsulate their state and take full responsibility for its management. I think that, in many respects, this idea is faithful to the original idea of objects and OOP -- perhaps more faithful than our current incarnation of them in languages with functions. I think that this could also help us in another way. Functional programming offers us one path to increased parallelism by eliminating state changes and thus making each computation independent of global context. Purely imperative programming offers another path, one that fits the early OO vision of encapsulated agents interacting via message passing. This is similar to the actor model that we see these days in languages such as Scala and Erlang. Of course, this model goes back to the work of Carl Hewitt, which inspired the evolution of both Scheme and Smalltalk! I have not thought through all the implications of my thought experiment yet. Maybe it's nonsense; maybe it's a solved problem. Still, I think it might be fun to turn the dial up to 10 on stateful programming and try to implement a non-trivial program with no return statements. How far could I go before things got uncomfortable? How far could I go before I found myself contorting the code in a way that serves the idea more than the program I was writing? Sometimes I am surprised just how many interesting thoughts can fall out of the simplest conversations. Too bad time to play with them doesn't fall out, too. -----