I have been involved with web software development for a few years now. Early on I learned the value of the web as a resource and spent plenty of time searching through documentation, articles, and blog posts, studying the methods others have used to deliver successful web applications. Certain practices and tools have stood out as I’ve taken in information on topics ranging from testing and web frameworks to proper HTML and CSS. One particular voice has been difficult to ignore: Ruby and its web development framework, Rails.
Always curious, I have worked through several of the more popular video and written tutorials that are prevalent online. I find them interesting, full of promise, and yet I feel they don’t give me the real picture of either Ruby or Rails. Sure, it’s cool that you can write your own trivial blog application in about 10 minutes, but I don’t write trivial software. Nobody cares about trivial software.
On the other hand I see respectable software developers using Ruby and Rails, so there must be more to it than what the typical tutorial shows. So, over the past few months I have been slowly digging into Ruby, working to really learn the language and not just the Rails framework. I want to see the whole picture of how to solve real, complicated problems using Ruby, and eventually Rails, and answer a few questions I have. Is it maintainable? Testable? Scalable? How does it compare to Perl? Would I enjoy programming in Ruby as much as I have enjoyed Perl? Layed out before you is part one: the beginning of my journey.
More on Perl
The better part of my development time over the past four years has been spent writing Perl. I’ve come to know the language well, learned how to take advantage of its flexibility, and I enjoy using it. Though some will count Perl as an old, outdated language, I believe their disparaging remarks are mostly unfounded, born of ignorance or personal taste for one syntax over another. Perl has a long history of real-world use and, despite an increase in the number of quality scripting languages available and their respective buzz, I see a bright future ahead for Perl. Not that I think Perl is God’s gift to programmers, but even COBOL is still in use.
Syntax
One of the things everyone seems to rave about with regard to Ruby is its clean, expressive syntax. So, what would make syntax clean or expressive? I suppose clean syntax would be very legible, having little to obscure the reader’s intake or the author’s creation of the text itself; expressive syntax, on the other hand, would convey a lot of meaning with a minimal amount of text. Does Ruby live up to this hype? My opinion is yes, to some degree.
Comparing programming with writing books or articles, I find it is normally the author who makes a particular text expressive and not the language. Though it does play a small, enabling role, a good author can more than make up for a poor language. As languages go, Ruby and Perl have a similar set of core features with sometimes significantly different syntax, much of that coming from Ruby’s declaration that everything is an object. Take the following examples:
Ruby
a = b.keys
5.times { puts 'hello' }
sorted = array.sort
Perl
@a = keys(%b);
for (1..5) { print "hellon" }
@sorted = sort(@array)
In comparison to Perl the syntax feels clean, uncluttered, and wonderfully free from excessive use of the shift key. I hadn’t realized how shift-key-dependent Perl was until I spent a few hours really writing Ruby. In Perl, every variable name, start and end of a block, and method invocation required the use of the shift key. Compare that to Ruby where only class and instance variables have sigils*, blocks can begin and end with plain english, and methods are invoked with a period. Especially satisfying to me was the method invocation, since in Perl it is a two-character ordeal (->) that I find embarassingly clumsy. And no, I don’t miss semi-colon line endings.
Overall, I like the syntax of Ruby. It really is a very legible language, thus being clean, and at the very least allows an author to accomplish a bit more with a bit less.
Variables and types
Everything in Ruby is an object, even the base types (Hash, Array, String, etc.). Everything in Perl is, um… different. This core difference between Perl and Ruby leads to a lot of other, occasionally subtle, differences in how variables and the languages base types work.
There is really only one type of variable in Ruby: it holds an object, or more correctly, a reference to an object. The variable doesn’t care if it is being assigned an Array or Hash object, they are both objects and that’s all it needs to know. One big advantage of this is that it reduces confusion and probably makes Ruby an easier starting point than Perl for beginning programmers. Take this Perl code as an example of the confusion that can ensue:
my $a = 1;
my @a = (1, 2, 3);
my $b = [1, 2, 3];
print 2 + @a, "n"; # yields 5 -- not what you wanted (2 + @a array length)
print 2 + $a, "n"; # yields 3 -- that's what you wanted
print 2 + $a[0], "n"; # yields 4 -- confusing...
print 2 + $b[0], "n"; # yields 2 -- shows a warning if enabled
print 2 + $b->[0], "n"; # yields 3 -- That's better
Another advantage of the base types in Ruby being real objects is that you can subclass them, making it easy to give your own classes Array or Hash indentification and behaviors. The base types in Ruby have a rich set of methods by default that make them easy to work with. One of my personal favorites is Array#join, which I use routinely to print nice, comma-separated lists. Array#each and Array#collect are also high on my list.
Probably one of my biggest gripes about Ruby is that it lacks Perl’s autovivification, which is especially handy when dealing with multi-dimensional hashes and arrays. Perl automatically creates a new hash if I attempt to assign to a hash reference that doesn’t yet exist. For example let’s say I’m creating a 3-level hash structure to store some data I read out of a file:
Ruby
@p = Hash.new()
@p[a] = Hash.new() unless @p[a]
@p[a][b] = Hash.new() unless @p[a][b]
@p[a][b][c] = 'blah'
Perl
$p->{a}->{b}->{c} = 'blah';
I do recall reading about the existance of a module for Ruby that would allow this same type of behavior, but I haven’t tried it out yet.
Variables and scope
Variable scope in Ruby is declared by the presence (or absence) of a leading sigil on the variable name, making it easy to determine at a glance. Variable names with no initial sigil are lexically scoped, as are most variables in Perl (declared with my). If a variable has an initial sigil, its scope is determined by that sigil: @var is an instance variable, @@var is a class variable, and $var is a global variable.
Perl lacks that sort of simple convention, likely because of the way its object model functions. Each of the different types of variable scoping Ruby provides can be accomplished in Perl, the intent just isn’t as obvious when reading the code. An incredibly flexible language, Perl allows developers access to do more deep, dark, powerful things than most people should really be given access to. Period.
Blocks
A block of code in Ruby is anything but boring. In fact, Ruby shames blocks in other languages, calling them names like “ordinary” and “simple”. While I don’t condone such behavior, I do like a Ruby block’s ability to receive parameters, and having two sets of syntax for denoting blocks is okay, too.
Probably the one bit of syntax that threw me off the most when I first read a block of ruby code was the definition of a parameter to a block. I just couldn’t figure out what |x| was supposed to mean — I’d never seen anything like that in a programming language before, other than perhaps shell script. I thought it was ugly. They say that beauty is in the eye of the beholder, and now that I understand what |x| means I find it quite a thing to behold (in a good way). Dare I say it even now feels natural?
# Print each element in the array
['one', 'two', 'three'].each do |x|
puts x
end
I mentioned a moment ago that a block in Ruby can be expressed in two different ways. There is the usual Perl-ish way (or Java-ish, or what have you), and there is a plain english way (perhaps Pythonic?). Use whichever feels most natural. Often times I feel typing end is faster than the curly braces, and reads more like a natural language.
# Curly braces...
['one', 'two', 'three'].each { |x|
puts x
}
# do ... end
['one', 'two', 'three'].each do |x|
puts x
end
This becomes even more interesting when you consider how easy it is to write your own iterator like Array#each using the yield operator. The yield operator calls the block of code associated with the method call, giving it the parameters you define.
# Define a class
class Blah
def initialize()
@b = ['one', 'two']
end
def my_each()
@b.each do |i|
yield(i)
end
end
end
# Run this thing
blah = Blah.new
blah.my_each do |x|
puts x
end
More to come
This post is getting long, so I’ll leave a few other topics for part II. Look for more on exception handling, object orientation, and code organization soon. Read part II now!