What would you do if you were "stranded" on a desert island and your only programming tool was a functional language, instead of more conventional object oriented language? Assuming the loss of OOP was indeed a problem, you would emulate OOP structure, easily, in a functional language, of course. Let's see one way you might do it.
First, in order to present an example, we are going to need a functional programming language. Ideally, it should be one that many of us are somewhat familiar with. That said, may I present:
JavaScript, The Functional Parts.
Javascript does most of what a "real" functional language does: functions are "first class" -- you can assign one to a reference variable like any other value; functions can be nested (which is implied by the next statement); functions can be used as closures -- maintaining references to variables from enclosing scopes (which allows you to do "currying", among other tricks).
So what is missing? One big thing is that most implementations do not optomize tail recursion. Also, javascript has no concept of immutable objects or "assign-only-once" symbols (many may not mourn the loss of assign-only-once, but it can have its place).
For the sake of the next exersize, let's pretend that JavaScript is a true functional (only) language, rather than an OOP/functional hybrid. That is, let's ignore all of the dot/pseudo-associative-array notation that lets an outer scope examine the nested variables/fields of a value.
The following is one way you might go about simulating OOP structures using closures:
Code | Notes | |
---|---|---|
|
Simulate a constructor by creating a closure to contain the instance variables for each invocation. The function new_person is acting as a closure by creating variables which are used by its own nested functions. If we had needed to emulate static data, we could have made an outermost function to serve as a context for the static data. This outer function would have returned the constructor function for the individual instances. This nested constructor would then itself be a closure with access to the static data for the class. |
|
|
Marry some code to the object as well as the data above. Certainly there is room to optomize this implementation of a method / message-dispatch table, but I am trying to stick with the most primitive implementaion, assuming little available in any given (functional) language. Here, we return functions to handle the messages get_name and get_geneology. |
|
|
Implement a pseudo-mutator (be_adopted_by) which constructs a new instance based on the old instance plus the desired changes. Assuming immutable data, this is how it has to work (construct a mutated clone). This method will be used (sort of) in the second example. |
|
|
Click the button to run the demo: |
|
|
Here is a way to emulate subclassing. Once again, we use a closure to contain the instance data. We also save a reference to the superclass instance, so we can reuse its message handlers, er, methods. In keeping with our message based method calling, we are also effectively using prototyping for inheritance (as opposed to compile time static method table setup). |
|
|
Click the button to run the demo: |
So far, so good. We can use a function that returns other functions as a message handler (a close approximation of a virtual method table). We can use closures to capture instance data.
Finally, a critique of the example: it would be nice to save a reference to the base class constructor to aid in cloning an immutable object; it would be nice have access levels on the various methods to limit the scope in which they can be used; it is of course not as fast as C++ as implemented (not that I particularly like C++). I'm sure you can think of other improvements, as well.
Contact me: |
r |
o |
b |
o |
p |
r |
o |
g |
@ |
yahoo.com |