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"
def foo
yield 100
end
puts( a )
foo{ |a| puts( a ) }
puts( a )
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 |