B
barcaroller
I come from a C/C++/Perl background and I have been reading up on Ruby for a
while (no hands-on experience yet, except for a few tutorials). Most of the
stuff sounds/looks very positive but I recently found this critique of the
Ruby language on the web and I was wondering whether these statements have
any validity at all.
========================================
Ruby: better than Perl - but what isn't?
----------------------------------------
Ruby is the second-most vulgar programming language in wide usage. It
succeeds at its intended goal of being better than Perl, but its design
manifests a total ignorance of basic programming language theory.
Updated 9 January, 2005: Bruce Eckel apparently isn't bowled over, either.
Ruby's creator, Yukihiro "matz" Matsumoto, crossed the Perl language with
Smalltalk-inspired OO features including a fully-unified type system and
closures, then added exception handling and simulated multi-threading. The
result is certainly an improvement over Perl, but it is terribly
disappointing as a language.
The main philosophy of Ruby seems to be, "Side-effects rock!" We can
probably blame the C language for blurring the distinction between
imperative and applicative code. Maybe that blurring makes some amount of
sense for C, which is essentially a high-level assembly language. However,
languages such as C++, Java, and Perl have carried that foul practice
forward. And now Ruby takes it to new heights: every statement is an
expression, and every expression is a statement. Every method is a
procedure, and every method also is a function. Functions and expressions
with side-effects abound in Ruby.
Worse, Ruby exalts global side-effects. In a nominally multi-threaded
language, this is unseemly to say the least. As an everyday example, the
statement
x = gets
reads a line and sticks it into x just like you'd probably expect, but it
also has the side effect of sticking the line into the global variable $_.
WTF???
Ruby seems to love the magical global variables carried over from Perl.
There are dozens of them, all with nonintuitive names like $_, $!, $*, and
$~. Yuck. These things get set as side effects, and often are used
implicitly.
Ruby's exception mechanism combines the above failures into an astounding
disaster. When an exception occurs, an exception object is created and
stored into $! which is a global variable. Apparently you aren't supposed
to get exceptions in more than one thread at a time. Updated 9 January 2005:
It turns out that this isn't actually an issue; read the comments for
details.
Ruby also blurs the line between names of variables and methods. The
Uniform Access Principle is an excellent idea. at least in a language where
both variables and methods have to be declared and cannot overlap. But Ruby
allows a symbol to identify both a variable and a method, and the
disambiguation process is best described as eccentric.
Ruby delights in the bizarre usage of operator overloading. "<<" normally
means "left shift", but it also means "here document follows," "append to
string," and "extend array." Other operators have similar illogical
overloadings; for example, the "<" operator not only means "less than" but
also "is a subclass of."
Ruby throws a basic OO principle to the wind by allowing anyone to add
members and methods to an existing class, even outside of the original class
definition. The methods thus added have full access to all other members and
methods, including private ones. The usual term for this is "breaking
encapsulation," although I dislike that term because it misuses the word
encapsulation. A better term is "violation of the Open/Closed Principle," in
that the original class is not kept closed against modifications.
Ruby's multi-threading seems to be a misfeature from tip to toe. Ruby's
multi-threading is simulated: it only runs on a single CPU and is
fundamentally incapable of taking advantage of multiple CPUs or multiple
cores within a CPU. Which is just as well, because Ruby doesn't define a
memory model for coordinating data between CPUs or cores. Then there is the
problem of global variables being changed as side effects and accessed
implicitly. Writing multi-threaded code in Ruby looks like a good way to
cause yourself immense non-deterministic grief.
Ruby code can be written to be very clean and readable-something that cannot
really be said about Perl-but Ruby can also be written just as poorly as
Perl is. Unfortunately, most of the Ruby code that I've seen, including
various introductory guides to the language, seems to prefer the slutty side
of Ruby: procedural code using global variables and magical side effects.
I'm
not sure that I see how Ruby is better than Perl in those cases.
I've written some Perl over the years, and I probably will be transitioning
to Ruby for those tasks. Ruby certainly is better than Perl, especially if
you choose the high road and write clean code that eschews the side effects
and global variables. But I'm not at all happy with Ruby, because it easily
could have been so much better than it is.
Friday, 7 January, 2005
while (no hands-on experience yet, except for a few tutorials). Most of the
stuff sounds/looks very positive but I recently found this critique of the
Ruby language on the web and I was wondering whether these statements have
any validity at all.
========================================
Ruby: better than Perl - but what isn't?
----------------------------------------
Ruby is the second-most vulgar programming language in wide usage. It
succeeds at its intended goal of being better than Perl, but its design
manifests a total ignorance of basic programming language theory.
Updated 9 January, 2005: Bruce Eckel apparently isn't bowled over, either.
Ruby's creator, Yukihiro "matz" Matsumoto, crossed the Perl language with
Smalltalk-inspired OO features including a fully-unified type system and
closures, then added exception handling and simulated multi-threading. The
result is certainly an improvement over Perl, but it is terribly
disappointing as a language.
The main philosophy of Ruby seems to be, "Side-effects rock!" We can
probably blame the C language for blurring the distinction between
imperative and applicative code. Maybe that blurring makes some amount of
sense for C, which is essentially a high-level assembly language. However,
languages such as C++, Java, and Perl have carried that foul practice
forward. And now Ruby takes it to new heights: every statement is an
expression, and every expression is a statement. Every method is a
procedure, and every method also is a function. Functions and expressions
with side-effects abound in Ruby.
Worse, Ruby exalts global side-effects. In a nominally multi-threaded
language, this is unseemly to say the least. As an everyday example, the
statement
x = gets
reads a line and sticks it into x just like you'd probably expect, but it
also has the side effect of sticking the line into the global variable $_.
WTF???
Ruby seems to love the magical global variables carried over from Perl.
There are dozens of them, all with nonintuitive names like $_, $!, $*, and
$~. Yuck. These things get set as side effects, and often are used
implicitly.
Ruby's exception mechanism combines the above failures into an astounding
disaster. When an exception occurs, an exception object is created and
stored into $! which is a global variable. Apparently you aren't supposed
to get exceptions in more than one thread at a time. Updated 9 January 2005:
It turns out that this isn't actually an issue; read the comments for
details.
Ruby also blurs the line between names of variables and methods. The
Uniform Access Principle is an excellent idea. at least in a language where
both variables and methods have to be declared and cannot overlap. But Ruby
allows a symbol to identify both a variable and a method, and the
disambiguation process is best described as eccentric.
Ruby delights in the bizarre usage of operator overloading. "<<" normally
means "left shift", but it also means "here document follows," "append to
string," and "extend array." Other operators have similar illogical
overloadings; for example, the "<" operator not only means "less than" but
also "is a subclass of."
Ruby throws a basic OO principle to the wind by allowing anyone to add
members and methods to an existing class, even outside of the original class
definition. The methods thus added have full access to all other members and
methods, including private ones. The usual term for this is "breaking
encapsulation," although I dislike that term because it misuses the word
encapsulation. A better term is "violation of the Open/Closed Principle," in
that the original class is not kept closed against modifications.
Ruby's multi-threading seems to be a misfeature from tip to toe. Ruby's
multi-threading is simulated: it only runs on a single CPU and is
fundamentally incapable of taking advantage of multiple CPUs or multiple
cores within a CPU. Which is just as well, because Ruby doesn't define a
memory model for coordinating data between CPUs or cores. Then there is the
problem of global variables being changed as side effects and accessed
implicitly. Writing multi-threaded code in Ruby looks like a good way to
cause yourself immense non-deterministic grief.
Ruby code can be written to be very clean and readable-something that cannot
really be said about Perl-but Ruby can also be written just as poorly as
Perl is. Unfortunately, most of the Ruby code that I've seen, including
various introductory guides to the language, seems to prefer the slutty side
of Ruby: procedural code using global variables and magical side effects.
I'm
not sure that I see how Ruby is better than Perl in those cases.
I've written some Perl over the years, and I probably will be transitioning
to Ruby for those tasks. Ruby certainly is better than Perl, especially if
you choose the high road and write clean code that eschews the side effects
and global variables. But I'm not at all happy with Ruby, because it easily
could have been so much better than it is.
Friday, 7 January, 2005