« September 2005 | Main | November 2005 »

October 19, 2005

Domain Specific Languages: Objective-C, Ruby and Java (and Groovy)

Listen to this articleListen to this article

I'm forever trying to "improve" my coding and design skills; I say "improve" because there is always the risk that I'm making changes for change sake. One thing I really try hard to do is remove any notion of getting/setting properties of objects and instead focusing on behaviour.

Now I've always tried hard to do this but it's a skill that definitely takes some time and constant practice. TDD certainly has made my life easier by giving me some tools for this but more recently I've really been making an effort to try and "design" my classes in a way that creates Domain Specific Languages (DSL). DSLs enable you to write code that is hopefully more readable and understandable and therefore easier to write, debug and maintain. (At least that's the ide in principle anyway.)

I use a variety of languages in my day-to-day work and I've found that the effort required in creating a DSL to be vastly different depending on the language. Of the few languages I've actually used in anger (Smalltalk unfortunately not being one of them) Objective-C really does provide a nice syntax for creating DSLs (once you get your head around the square brackets).

For example, take the age-old problem of transferring money from one account to another. In Objective-C, assuming we have an Account class with a transfer() method, we can write something like this:

id source = ...;
id destination = ...;

[source transfer:20.00 to:destination]

* Using floats for currency is generally a bad idea but it'll do for illustrative purposes here :-)

Notice the use of named parameters to really help convey the intent. This is actually an optional feature—you can still use positional arguments if you like—but one I use exclusively.

The transfer() method might look like this:

-(void)transfer:(float)amount to:(id)destination {
    [self debit:amount];
    [destination credit:amount];
}

Again, ignoring the unfamiliar method declaration (you'll just have to trust me when I tell you that you do get used to the language and even love it), it's all pretty nice and readable.

Essentially, when calling the method, the identifier that preceeds a colon serves as the name of each argument—ie as used by the caller— with the method name itself serving as the name of the first argument and to for the second.

Once inside the method, the identifier after the colon serves as the name of the argument to be used: amount and destination.

All up, Objective-C is very concise and allows for the creation of fairly nice DSLs without much effort at all. In fact from what I can tell, most Objective-C code turns out to be more-or-less DSL-like; it's typical to see methods calls that look like:

[report printTo:printer withPagination:YES]

The next example I whipped up uses Ruby. Now, I have to admit that I have all of about 3 days of Ruby experience so if you can come up with a better way please, please, please let me know. So, caveats aside, here is the same example in my bestest Ruby, again starting with the usage:

source = ...
destination = ...

source.transfer :amount=>20.00, :to=>destination

This uses a ruby hash—an associative array like a HashMap or Hashtable in Java. You usually need to wrap the hash definition in curly-braces but this can be omitted when the hash is used as the last—or only—parameter.

Now for the method itself:

def transfer params
    amount = params[:amount]
    self.debit amount
    params[:to].credit amount
end

Pretty good really but I still have a preference for the Objective-C use of named parameters. I did read in Programming in Ruby that named parameters was to be a feature of Ruby at some point but hasn't yet made it. I also read somewhere recently that Ruby 1.9 will have a slightly simpler calling syntax so the invocation will look like this:

source.transfer amount:20.00, to:destination

The only Ruby-based DSL I know of is Rake but again my experience with Ruby is somewhat limited.

And finally Java, IMHO the ugliest of the bunch. To achieve something similar in Java seems to me at least (and again, somebody prove me wrong puhlease!) that named parameters with an even remotely useful syntax requires a combination of inner-classes and method chaining. So, to achieve a calling syntax like this:

Account source = ...;
Account destination = ...;

source.transfer(20.00).to(destination);

Requires something at least as complicated as this:

public class Account {
    ...

    public Transfer transfer(float amount) {
        return new Transfer(amount);
    }

    public class Transfer {
        private final float amount;

        Transfer(float amount) {
            this.amount = amount;
        }

        public void to(Account destination) {
            Account.this.debit(amount);
            destination.credit(amount);
        }
    }
}

The best example of a Java-based DSL that I can think of would probably be JMock.

And finally, by popular demand, a Groovy example. Groovy currently supports named parameters for calling methods that accept a Map so the calling syntax is a lot like Objective-C:

def source = ...
def destination = ...

source.transfer(amount:20.00, to:destination)

The transfer() method itself then becomes something like:

void transfer(params) {
    def amount = params.amount
    this.debit(amount)
    params.to.credit(amount)
}

Which looks unsurprsingly like Ruby. Alas, I have no real-world example of a Groovy-based DSL to show you.

October 04, 2005

The Computing Disease

Listen to this articleListen to this article

My iPod has been getting a real workout lately. I've been getting into podcasts and audible books. I've never seem to make the time to read paper books anymore and when I do I always manage to fall asleep after a few paragraphs so listening to them instead works well out particularly for me.

The current book is The Pleasure of Finding Things Out by my all-time favourite physicist (yes I have a favourite), Richard P. Feynman. I've always liked Feynman, mainly because his approach to life and learning seems to fit with my ideal—not necessarily reflected in reality but I do try.

Over the years I've read a number of his books, papers and lectures etc. and he always seems to have such a great outlook on life, learning, love, you name it. IMHO, a man with his head screwed on just right. I especially like his lectures on physics and his thoughts on computing. He has a way of making difficult material accessible to the likes of yours-truly.

Among many other things, Feynman states that knowlegde without understanding is pretty much a waste of time; the idea that just being able to perform some function or know the name of something without undertsanding what you are doing or the nature of that something, is not only pointless but inefficient and makes you largely ineffective. A subject that is very close to my heart also.

Yesterday I was listening to one of his talks on his time at Los Alamos on the Manhattan Project. He was talking about how they developed sophisticated—even by today's standards—algorithms for utilising many computers—adding and multiplying machines—in parallell. The problem was that although they had ordered a number of IBM machines, it would be sometime before the machines would arrive and even then they woudl need to be assembled. In the meantime they decided to start writing and debugging their programs. To do this, they enlisted the help of a group of women to act as the adders and multipliers—like a typing pool only performing calculations instead. Amusingly, because of the way the algorithms worked and because of the state of technology at that time, the women managed to process the data as fast as the machines could. The only problem was that the women got tired and needed sleep, food, etc.

Anyway, in all this, Feynman makes a great quote which tickled my fancy:

There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them! - Richard P. Feynman

Of course we all prefer to call it "innovation" ;-) but at least it's nice to see that the phenomenon isn't a recent one—apparently even the great Von Neumann was afflicted.