The pursuit of perfection
When I read Adam Conner’s post on Ruby and what he dislikes, primarily compared with Lisp, I was reminded of a tendency that I have: perfection über alles. It’s an admirable thing to keep a healthy skepticism about the real-world nature of things versus what could be, but it’s also necessary to be realistic sometimes. I wanted to take his points in turn.
First, he speaks of “more than one way to do it,” which is a valid but specious point. All languages have multiple ways to do things. It may be true that some languages encourage more strict approaches—certainly Python attempts to provide only one way to do things, or certainly one preferred—but even in those cases, there are multiple ways. Lisp actually has a nearly infinite way of doing things, especially when you include all the things you can do with macros and other functionality.
The argument actually touches a tangential truth: that each way be obvious when read. One of the primary complaints about Perl is its obfuscation factor. This is actually not about having multiple way to do something, but instead that almost all of them are potentially unclear when read months later. So far, I’ve noticed that Ruby code written by others is almost always more readable than most other languages1. The one place where that falls completely apart is in meta-programming, but this is no worse than trying to reverse analyze a Lisp macro.
Second, he refers to some of the more baroque syntactic constructions, like the use of $-variables. I hate these with a passion. I can’t even begin to explain how much I hate them, but there they are. Fortunately, the English module solves a lot of this. I use it on all of my code, and I wish others would as well. There have been rumors that it may become standard facility, so you don’t have to include it yourself. This would be a huge step forward, and would likely introduce zero backward-compatibility issues.
Next, he brings up a lot of things adopted from Perl, such as ranges, which are not the most beautiful things in the world, but I actually find quite readable. It really depends on how you use them. Here’s one use that I dislike, taken from the Pickaxe book:
while line = gets puts line if line =~ /start/ .. line =~ /end/ end
To me, that’s not really that readable. There are better ways to express it, as well. There are other times that ranges are wonderful, such as for their use as Intervals:
kind = case year when 1850..1889 then "Blues" when 1890..1909 then "Ragtime" when 1910..1929 then "New Orleans Jazz" when 1930..1939 then "Swing" when 1940..1950 then "Bebop" else "Jazz" end
This I find actually clearer than most people’s writing with bizarre if/case constructs. This to me is very clear, which is the ultimate goal of all programming for me. I don’t deny there are some bizarre ways to write things, but then again, there are in every language. Whether you use them or not is your decision.
The next complaint about the significance of whitespace is a bit of a red-herring. Every language I can think of, except Lisp, has some bizarre whitespace significance. Lisp gets around it through the use of the S-exp notation, which is both its strength and the single thing that is intimidating to most people. I like it, but it is something that breeds religious behavior. While he takes a side-swipe at Python, I think that the significance of whitespace2 is actually a benefit for languages
Another place that seems to confuse the author is the idea of constants not being actually “immutable.” I think this is a mistake often made with dynamic languages, including Lisp. Many things in Ruby are immutable, just as they are in a lot of languages. Variables are not immutable, they are simply names for a reference to an object. What the author seems to want is a one-time assignable variable, which might be interesting. I find the behavior of warning based on convention to be more than suitable for the nature of my development. Even the DEFCONSTANT form can be defeated if you’re an idiot.
He has a few other complaints, which I won’t go into, but this is what it comes down to:
But it’s not Lisp. I came to other languages before the conversion experience; Ruby falls afterwards. Sure, the Lisp community is dysfunctional, and its libraries and toolchain have issues. Utterly impractical yadda yadda ya. But Lisp is the culmination of a certain line of thought, and Ruby is just a waypoint. Where Lisp exposed me to first principles, Ruby has some clever syntactic hacks. It isn’t that I despise all other languages. But if you’re going to go for dynamic languages, why settle for 80% of what can be done when you could have 100%? Lisp is a tough act to follow. It changed my expectations.
Indeed, it’s not Lisp. And Lisp isn’t Smalltalk. We could go into the issues with CLOS for hours, and the inanity that exists with certain intensely baroque elements of Lisp, but it too is an imperfect language. I love Lisp for its purity of concepts—mostly—but other than a few specific places, it is even less practical a choice than Smalltalk for most organizations. If I were developing a huge NLP system, Lisp would be my first choice. If I were modeling some amazingly complex real-world system, like financial markets, I’d use Smalltalk. For most other projects, languages like Ruby—and strikingly, even Java—are actually more practical.
The author admits that the libraries and toolchains for Lisp are lacking. This is an understatement, especially when discussing the free community. Franz has some amazing tools in Allegro Common Lisp, but the free world, while having some great Lisp compilers, has a pretty atrocious collection of libraries. Like Smalltalk, it seems everyone ends up re-inventing everything every time. This is unfortunate. As much as I love writing Smalltalk, I always feel like I’m having to write a lot of things that I shouldn’t have to write.
For me, Lisp and Smalltalk are my “secret weapon,” to be pulled out for pleasure and for truly hard projects. Most projects aren’t hard.
1 Smalltalk is the one exception to this, however Smalltalk is more explorable largely because of its environment, not the language itself. While I prefer the syntax of Smalltalk, it’s not an order-of-magnitude better than Ruby.
2 This is a “within reason” caveat, of course. FORTRAN is absurd in this regard, at least in its early punch-card derived nature. Python only cares about relative whitespace, not absolute whitespace.
This entry was posted at 12:25 pm on 2 July 2006 and is filed under Programming. You can follow any responses to this entry through the post-specific RSS 2.0 feed.
No comments found.
Both comments and pings are currently closed.