I few years ago, before I delved into functional programming, I had a small stint with Flex/ActionScript. ActionScript is an imperative language very similar to Java. At the time, I needed a very simple state machine, which had a single path of execution (basically a chain of commands). The design included a chain object, which joined command objects and executed them sequentially as long as no exceptions where thrown. Because these chains where also used for transformations and had dependencies (one command might compute something that is needed by another command), the commands had to keep state, though a global context object was used to store/retrieve state. I’m sure there are other ways of designing such a system, but it turned out to be pretty maintainable and rather clean. One thing that bothered me at the time were the implicit dependencies amongst the command objects, which relied on certain context information to be there in forms of map keys, which means if a command changed how it stored a particular results, its dependents would have to be modified as well. Because of the lack of static typing and runtime inference (unless done at each command object level), there was no way to ensure that something wasn’t silently failing. The problem was due to utilization of map structures for context storage which besides not having any static typing abilities, also didn’t allow the chain invocations to perform runtime inference of argument matching. The implementation was very functional and wasn’t too badly designed, but definitely not very pretty.
I don’t have access to the exact code at this time, but below is a simple example that demonstrated similar issue in Java.
Running the above yields:
Results: result1: 1234 result2: 2468
Besides the mandatory java ceremony, it’s also not apparent to me that this can be accomplished any better without the use of reflection, which of course would add yet more boilerplate.
Macros to the rescue. If any of you aren’t familiar with what makes lisp (besides its simple syntax allure) so powerful, you should familiarize yourself with macros. The example I give below doesn’t even make a dent into the possibilities of macros.
With a simple macro
The above can now be utilized with the following api…
Yielding (in SLIME REPL):
Executing first Executing second: first arg Executing third: second arg random-arg nil
Running a similar script with an added parameter in the third command that doesn’t exist in the chain
Throws an exception (in SLIME REPL):
'does-not-exist' argument is required! [Thrown class java.lang.Exception]
Of course the above can be much improved, one off the top of my head improvement is to allow default values for arguments that don’t exist and possibly be able to specify arguments who’s lack of should throw and exception an in other cases either bind a nil or default value. But the concise example demonstrates similar abilities of my java program but with added runtime argument name matching. I’d love to see if the same can be accomplished with a statically typed language with type compile time vs. runtime argument checking. Going to investigate this with Haskell and Scala this week.