Home
Archives
About us...
Advertising
Contacts
Site Map
 

ruby in steel

 

Ruby


Ruby is very much the programming language of the moment. It has a lot going for it: highly object orientated, easy to learn, fast to develop, it could be the ideal language from anything from a simple ‘script’ to a complex web application. Here Huw Collingbourne and Dermot Hogan discuss why they have been seduced by the attractions of Ruby in spite of significant reservations…

Ruby is an object oriented, interpreted, cross-platform language which may be used for many of the same sorts of applications as Perl or Python. Ruby was created by Yukihiro Matsumoto (commonly known as ‘Matz’); it was first released in 1995. The current stable version is 1.8.4; version 1.9 is in development and, a more significant rewrite, version 2.0 is promised at an as yet unspecified date. Over the past couple of years, the new Rails framework for Ruby (commonly known as ‘Ruby on Rails’) has attracted a good deal of interest. This is an easy to use programming framework which provides Ruby with many of the web development features which you might more usually associate with PHP. In spite of its potential, Ruby On Rails is currently supported by few commercial web hosts. For a hands on introduction to Ruby programming see the Bitwise Introduction To Ruby.

Huw: You’ve been very critical of Object Orientation in the past. Has Ruby made you change your mind?

Dermot: To me, OO is a tool - not a way of life or a religion. My main objection to OO is that people use it as a substitute for serious analysis of the problem in hand. OO is good where you can ‘program by difference’; it’s not so good when you use it as the basis of an entire design where the differences between different subcomponents can be large. The real problem is that ‘techies’ get carried away with the elegance of OO and don’t apply sufficient serious thought to design. This is reinforced by the pretty low intellectual demands imposed by so called ‘computer science’ courses at colleges. Anyone who thinks that you can learn the principles of good design by studying Java is out to lunch – but I digress. Ruby doesn’t add or detract from that fundamental problem, but I do like the way that you can ignore OO if you want, yet it’s built into the language at a very deep level. That’s neat.

Huw: Matz has said that, with Ruby, he has ‘tried to follow the principle of "least surprise."’. I don’t know about you, but I am constantly surprised by Ruby. To take a few examples:

  • I am surprised that a block is not an object. If I create a block in Dolphin Smalltalk it is a true object with an independent existence. When I ask it to tell me its class it replies BlockClosure. In Ruby, a block only exists when it is either appended to a method or when you (as Matz says) “objectify” it by wrapping it up in a Proc object. If I ask it to tell me its class it replies “syntax error”!
  • I am surprised that block parameters (in theory, local to a block) can initialize variables of the same name which exist outside the block. Here’s an example:
a = "hello world"    # a is a local variable
def foo              # foo is a method 
  yield 100          # this passes 100 as an argument to a block
end
puts( a )            # a is “hello world”
foo{ |a| puts( a ) } # |a| here is a ‘block parameter’ and the block
                     # between { and } is passed to the foo method
puts( a )            # outside the block, a is now 100!
A ‘Block’ contains code that can be sent, sent like an ‘anonymous function’ to a method. The receiving method is able to execute the block and pass values to its ‘block parameters’ (variables between upright bars declared within the block). Blocks are much used for iterating over lists and arrays in Ruby.

I am even more surprised that encapsulation is broken to the extent that there is even a method that lets you poke new instance variables into an object! This is actually documented in the Ruby code itself as “thereby frustrating the efforts of the class’s author to attempt to provide proper encapsulation”. Am I just easy to surprise? Or are there things about Ruby that catch you by surprise too?

Dermot: I have to honestly admit that I haven’t had such a jaw-dropping feeling as I have over Ruby since I last worked in a large bank. Banks have ways of screwing things up that you simply wouldn’t believe! And it’s the same with Ruby. Syntactically it’s a mess – it’s quite possible for source to have different effects depending on whether there’s a linefeed or a space or not. The encapsulation – the raison d’être of OO - is shot to pieces, as you point out. Then there’s the non-constant ‘constants’. I still can’t figure out whether altering a ‘constant’ is a language feature or a bug. In any other language, it would be a bug! But in Ruby, who knows? The trouble here is that ‘Ruby is what Ruby does’. There’s no clear, written down grammar or semantics for the language. The ‘manual’ that you get is hopelessly inadequate or just wrong.

Huw: Ah yes, the inconstant constants! They had me fooled for a while too. This is a little experiment I tried out just now. Here, X, Y and Z are, in theory, constants (Ruby constants start with capital letters). My code has three goes at modifying these. First I try to assign a new integer value to X, the I try to append a string (<< concatenates) to Y; and finally I concatenate a string to Z and assign the result to the variable, myvar.

X = 10
Y = "hello world"
Z = "hello world"

X = 20
Y = "byebye" << "abc"
myvar = Z << "xyz"

puts(X)
puts(Y)
puts(Z)

At the end of all this, you would expect that my attempts to assign new values to X and Y would fail completely. In fact, Ruby allows it but gives a warning message. But it’s the last assignment that really gets me:

myvar = Z << "xyz"

Here I am appending “xyz” to the constant, Z, “hello world”, and assigning the result to myvar. Naturally, you would think, the constant Z. remains as it started, with the value “hello world”. But nope. When I print it out I see it has become: “hello worldxyz”. And this time, Ruby didn’t even warn me!

It’s things like this – these unpredictable side effects – that drive me up the wall about Ruby. Potentially it’s a very nice language indeed. But with so many gotchas waiting to leap out and bite you, how can it hope to be taken seriously for professional quality development?

Dermot: Well that’s a real problem. The thing about Ruby is that it’s very easy to get carried away with some of the nice features and forget about the things that will bite you. It might be quick to develop in, but there are an awful lot of loose ends around. I’ve always found that it’s the details that get you – the fact that something deep in a class library does something totally unexpected which causes grief down the line.

Huw: I know you’ve done a great deal of programming in Perl over the years. How does Ruby compare with that?

Dermot: I can only speak for Perl 5 – I don’t know much about Perl 6 yet. Perl’s great strength is that it treats regular expressions as first class objects. So does Ruby. But it seems to me that Perl is better here. It has a simple substitution syntax whereas with Ruby you have to use a method. But Perl’s OO is simply awful. It was never designed with OO in mind and it shows. Trying to debug OO Perl is the stuff of nightmares. It’s bad enough trying to debug non-OO Perl if it hasn’t been written by yourself. Trying to debug someone else’s OO Perl can be very, very difficult. Especially if it’s been written by a clever programmer who wanted to show what he (or she) could do with Perl. One of Perl’s weaknesses is that there are so many ways to write the same thing. With Ruby there are far fewer, so it should be easier to maintain.

But you’ve written more in Ruby that I have. Is it as slow as people say? I can’t say I’ve noticed – but then I haven’t written a big application yet.

Another thing I can't figure out is how people work without a decent debugger. The standard Ruby one is pretty unpleasant.

Huw: I’m not sure how slow Ruby would be in a huge application as I haven’t (yet) written a huge application in Ruby! To be honest, I don’t even think I’d want to undertake a major development in Ruby at the moment for the reasons you mention – the lack of good development tools. I’ve recently started to use ActiveState’s Komodo, which at least has a decent editor, a reasonable debugger and a certain amount of code-completion (a kind of IntelliSense). But the visual designer is a bit clunky. You have to design dialogs, save them back as code then wire the whole lot together. If you are used to a fully integrated visual designer as in Visual Studio or Delphi, this looks like a real blast from the past. Still, it seems to be the best there is at present.

Dermot: Visual design is always a bit of a problem with scripting languages. People who write scripts don’t think visually and so don’t really want or need a full blown IDE. So IDEs tend not to be produced at all or are only produced as an afterthought and aren’t very good. Certainly not as compared to Visual Studio or Delphi. There’s also a certain “we don’t need a steenkin’ IDE” approach around in Unix programmers. If VI and EMACS were good enough in 1970, they’re good enough now. I beg to differ: EMACS and VI should be consigned to the dustbin of history.

Huw: Ruby attempts to be a syntax-light language. In particular, it is line-oriented, which means that a linefeed generally terminates a statement much as a semi-colon does in C-like languages. It also lets you omit parentheses when passing arguments to methods. I can see the attraction of this approach – it makes code fairly free of punctuation and easy to read. However, it can sometimes lead to a ambiguities (it isn’t always clear, for example, when something that follows a method name is itself another method and when it is an argument). What’s your view? Is Ruby on the right tracks here or is it gaining ‘easy readability’ at the expense of real code clarity?

Dermot: Ruby ‘line oriented’? Give me a break! It might have started OUT like that but it clearly isn’t now. The line continuation character is honoured more in the breach.

You are right about parentheses. Ruby tries to make a distinction between a ‘command’ and a ‘function call’ – command being a function call without parentheses. Internally, the parser ties itself in knots trying to sort things like that out. It is certainly quite nice to be able to say foo bar and not foo(bar). But I think the cost in ambiguity is too great. I would not like to write a script that ran, say a nuclear power station in Ruby. You might get some unexpected results!

The big problem with code isn’t writing the stuff. Any fool can do that (and plenty have). The trouble – where the real costs lie – is in maintaining it. If you have to spend twice the amount of time getting the code ‘into your head’ to fix a problem, it’s twice the cost. The best language I’ve ever come across for clarity is Pascal. I’ve never maintained any Pascal code but I think it would be easy. The worst I’ve come across by a very long way indeed is C++ (I can think of one particular application where the code positively glowed pale blue in the dark: I still break out in a cold sweat thinking about it). I think that Ruby lies at the Pascal end of the spectrum. It can be very clear, but it also can be very ambiguous. I hope that Matz enforces proper parentheses in Ruby 2.

Speaking of which what’s the scoop on Ruby 2?

Huw: I’ve been trying to keep track of what’s happening with Ruby 2 but it’s not that easy. There are a good many discussions online about what Matz is doing, what he may do, what people would like him to do and so on. But a lot of it seems to be in the realm of ‘maybe’ and ‘some time’. I’m not at all clear on what actually will be in Ruby 2 or when it will appear. As far as one can gather, the principal idea behind Ruby 2 is to clean up some of the messy stuff that’s accreted to the current version of Ruby over the years – for example, the nastier elements of block scoping are going to be fixed; there will be a clear distinction between statements and expressions; and there is also a hint that some kind of optional typing may be introduced but it’s not at all clear what form that will take; and it will also compile to bytecode that will run on a virtual machine called Rite. But the Ruby community has been discussing all this for a few years now and I haven’t yet seen any announcement of when it’s likely to appear.

Dermot: Ruby 2 looks like ‘sometime, never’ to me. Ruby 1.9 is supposed to be the experimental version of Ruby 2, but I get the feeling that it’s taking a lot longer than anyone expected. I also don’t think that fooling around with 1.9 is the right way to do this stuff. To my mind, the Ruby parser and syntax is fundamentally flawed – it would be better to start again, preferably with something more modern than a 25 year old C-based YACC system.

Also, Matz seems to want to do everything … define the language, write the code, even down to the Ruby Virtual machine. That’s a very tall order indeed.

Huw: Look, in all this discussion, it sounds as though both of us have been picking holes in Ruby. Anyone would think we didn’t like the language. That obviously isn’t true. In recent times I’ve been spending most of my time programming, and writing about, Ruby. And you seem to spend about 15 hours a day working on a Ruby IDE for Visual Studio. So, obviously, both of us must feel that Ruby is a pretty interesting language. Let’s wrap this up by trying to pick out the features that appeal to us. For myself, I think I’d say that it’s the combination of reasonably thorough object orientation with a lightweight syntax. In my experience, Ruby is the most truly OOP language I’ve ever used with the sole exception of Smalltalk. Now, I am not completely obsessed with OOP – but it seems to me that either a language should do object orientation properly or it should leave it alone. Having decided to go for OOP, at least Ruby has, unlike most other supposedly ‘OOP languages’ done it thoroughly. And, unlike Smalltalk, it has a simple syntax and isn’t weighed down by being embedded into a hermetically sealed world – the entire environment that Smalltalk is obliged to carry around with it. In short, Ruby is, in principle, a perfect Rapid Application Development language. It is what Visual Basic .NET should have been. But it does badly need better development tools.

Dermot: I’d agree there. Ruby is one of the most interesting languages around – certainly, the most interesting that I’ve seen in a long time. It makes a pleasant change from the endless variations of the C syntax that seem to come out (C++, Java, C# and so on). I particularly like the fact that while it is indeed object oriented, you don’t need to know that to do simple stuff: I think mixins are brilliant!

Mixins provides a means whereby methods and constants defined in a separate module can be included in a class. In principle, this provides some of the benefits of multiple inheritance without some of the disadvantages.

And while I complain about the syntax (I’ve lost count of the number of times that I’d like to do something unpleasant to Matz!), writing a parser for Ruby, as I've been doing, is a whole lot different from using the Ruby language itself to do something useful.

Unlike Java, I have a lot of good feelings about Ruby. The thing I didn’t like about Java was the hype: it was going to blow away Microsoft, run your pop-up toaster, revolutionize the web and so on. None of this has happened and nor is it going to. At the bottom, Java is just another C retread. But with Ruby, the excitement is from the ground up, there’s no Scott McNealy making preposterous statements – just ordinary programmers using Ruby to get a job done. And done quickly too. Just like Visual Basic used to be, in fact. Now that’s a strange thought – could Ruby be the new VB?



Bitwise editor, Huw Collingbourne, is currently writing a Ruby programming tutorial and reference guide.   Bitwise Technical Editor, Dermot Hogan, is developing the Steel IDE for programming Ruby using Visual Studio 2005.

April 2006


Home | Archives | Contacts

Copyright © 2006 Dark Neon Ltd. :: not to be reproduced without permission