Coding in English
I've been programming computers, professionally, for over eleven years now (and programming in general for over twenty). In that time, I've tried a number of different programming environments and languages.
Delphi (Object Pascal),
Java (upto 1.4),
Smalltalk,
Ruby,
Python
and
C#,
Visual J++,
VBScript/Visual Basic,
Realbasic
as well as
Ansi C,
C++ (Borland C++ Builder, Visual C++, Ansi C++),
Objective-C (only a little bit),
PHP,
Lisp (at least some variant of it that was designed by someone at my university),
x86 assembler.
The languages and environments I like are in the first group, the ones I dislike in the latter group and the middle group are "almost but not quite". The question is what do they have in common?
Simple: it is easy to make them read and write like English.
Yeah, it's a bit subjective.
You could argue that Java and C# belong in the same group (I'll get to that in a bit). But the last group are quite happy chucking weird syntactic pieces into the mix - it makes my head hurt trying to remember when you need a & and when you need a * in the C languages. I have to say that Ruby, at first, put me off with its @s and @@s.
What about Java and C#? It has to be said that syntactically they are both very clean. But why is Java in the "good" group and C# in the "maybe" group? Because when I met Java it was cleaner than everything except Smalltalk. But when I met C# my frustration with static typing had boiled over. By the same token, Delphi now belongs in the "maybes" whereas, at the time, it was firmly in the "goods".
But, overall, Ruby wins. Code like:
dave.punch george unless george.is_hard?
(I'll never tire of that example).Or:
using :lame do
encode '/my/audio/file'
end
(a real bit of code that only executes the block if the given the 'lame' command is present within $PATH)Or:
hit nail, :with => hammer, :on => head, :at => :maximum_force
The latter is a pattern I often follow - using Ruby's hash as a way of building named parameters. This is something I learnt from Smalltalk, which was originally intended to be usable by seven year olds (hit: theNail :on theHead :at #maximumForce.). This makes the method definition look something like:
def hit object, options = {}
using = options[:with] || my_default_implement
where = options[:on] || my_default_area
force = options[:at] || my_default_force
... some code ...
end
The key thing here is that the options keys do not match the actual variable names because they serve different purposes. The options keys are for the users of the method, the variable names for the implementors.
Likewise, Ruby's arrays combined with blocks give you a whole load of power in a very small amount of text.
Given the choice of using Array#inject or writing something more verbose I will always go with the verbose.
collection.inject(0) { | sum, obj | sum += obj.details.size }
versus:
total = 0
collection.each do | item |
total += item.details.size
end
return total
(OK - not the best example). But, to me, the intention of the second version is immediately apparent whereas the first takes a second of squinting to figure out.
I was recently presented with something looking something like this:
sort{|a, b| index.collect{|i| (a[i] || 0) <=> (b[i] || 0))}.compact[0] || 0}
With apologies to the author, I'm still not sure what that does.
Readability is everything. Code spends longer in maintenance than development. And choosing your tools correctly can mean that, with minimal effort, your code can look like English.
No comments:
Post a Comment