Comparing Python to Perl and Ruby

Anyone who knows me well, knows that I am really into programming languages. Like editors, a programming language is a tool which is supposed to make your programming task easier.

Unlike the typical programmer, I have experience designing and implementing languages. Slick-C, the macro language in SlickEdit, is the third fairly major programming language I’ve been involved with. My experience and passion for programming languages gives me quite a bit more insight into performance and elegance.

I started learning Python because SlickEdit needed better support for the language. Unlike Ruby, I never heard a lot of hoopla about Python. The programming world has many, many scripting languages, most of them poorly designed. I figured that Python was probably just another poorly designed language with little or no technical merits.

I’ve been puzzled by the popularity of Perl since it has so many flaws. By the way, just because I dislike some elements of Perl doesn’t mean I will direct SlickEdit not to provide great support for it. SlickEdit language enhancements are based on popularity, and currently Perl is more popular than Python. However, that doesn’t mean I won’t rank on it a bit. Heck, I rank on C/C++ and it’s the language I use most (beware of sharp knife). To date, we have spent WAY more time on Perl and Ruby support than Python. This will always be the case, because it is WAY easier to implement Python support.

I have done my best to make these comparisons unbiased. The only code that I have written for these languages is sample code to better understand these languages. I do have good experience in parsing these languages either for color coding or tagging symbols for SlickEdit. My opinions are based on what I think make a state-of-the-art language. My next article “A Deeper Look at Python”, will talk more about Python and what things make a language state-of-the-art.

This comparison of Python, Perl, and Ruby is from a grammar perspective and does not cover the run-times of these languages. There are often cases where you end up choosing a language due to its run-time features. I’m not going to cover run-time features here. A detailed chart of reasons to choose one or the other which includes run-times would be very useful though.

Python Versus Perl

Python beats Perl by a mile. In a nut shell, Python and Perl have similar language features but Python is way easier to learn and use than Perl. Here are some specific examples:

Perl
[cc lang="perl" lines="100"]
sub func { # You’ve got to be kidding parameter passing.
# Perl 6 intends to fix this.
my ($x,$arrayRef)=@_;
$i=2; # Crud, this modifies the callers $i.
++$x;
${$arrayRef}[0]=4; #YUCK! Modify the callers array.
# By default, all variables are global in Perl. This
# is potentially more dangerous.
$newvar= ‘abc'; # this is a global variable
print $x,”\n”;
return(1);
}
$i=1;
# Choose the right variable prefix for a list
@array= (1, 2);
#Passing an array by reference is ugly
$x=func(1,\@array);
print $newvar,”\n”;
print “i=”,$i,”\n”; # i is 2
# You’re kidding, I need to change the prefix
$array[1]=0;
print $array[0],” “,$array[1],”\n”; # prints 4 0
[/cc]

Python
[cc lang="python"]
def func(x,array,z=’Cool! Default value’):
i=2 # This declares a new local variable
x+=1 # Hmm…No ++ operator in Python.
array[0]=4; #Modify the callers list
print x,z
newvar=’abc'; # This declares a new local variable
return(1)
i=1
array= [1, 2] # Python calls this a list
# Passing a list by reference works like
# the C# List generic.
x=func(1,array)
#print newvar; This won’t compile
print “i=”,i # i is 1
array[1]=0
print array[0],array[1]; # prints 4 0
[/cc]

Python is a big improvement over Perl. I would provide more reasons why Python is much better but I’d like to keep this article short. I will say that Perl has a very large and arguably cryptic grammar. Perl is hard for others to quickly read and understand. I find Perl hard to write as well. Because Perl has a lot of syntax which is so different from other programming languages, you quickly forget it and must read the language documentation again.

Python Versus Ruby

Comparing Python and Ruby is not as simple as showing some small snippets of code as I did above. For me, Python is clearly a better language than Ruby but I can understand why some people might like Ruby better. Ruby took the “kitchen sink” approach. It has language syntax for pretty much all the features of Perl, Python, and then some. Ruby embraces many of Perl’s complex features, which may make Ruby seem more familiar to the Perl fanatic than Python. There are loads of “shorthands” and optional syntax. To the naive person, lots of features give the false impression that the language is better or somehow more powerful.

While more can mean better, it definitely doesn’t in Ruby’s case. Due to the very large grammar, Ruby is way more difficult to learn than Python. The comment on the Ruby web site about Ruby being easy to learn is definitely not true. Reading Ruby code written by someone else is a problem too since others will use constructs you are not familiar with or don’t like. The ambiguities in the language make it much harder for editing tools to provide smart editing features. I’m not willing to give up smart editing features for shorthands which save a few characters. If you are using a dumb editor, then you might see this differently.

In order to keep this article short, I will not show all the constructs in Ruby which make it a large ambiguous grammar. So this may look like I’m nit picking.

Poor Ruby Syntax Choices

Here are some poor Ruby syntax choices:

Ruby
[cc lang="ruby"]
# Due to these poor choices…
if i<5 then
puts i
end
while i<10 then
i+=1
end
# This syntax for the shorthand forms is hard
# to read for most of us.
puts i if i<5
i+=1 while i<10
# The syntax below bloats the language.
puts i unless i>=5 # Same as “puts i if i<5"
[/cc]

Python
[cc lang="python"]
# These long hands are easily compressed
if i<5:
print i
while i<10:
i+=1

if i<5: print i
while i<10: i+=1
[/cc]

Ruby should have chosen a syntax which allows for a more conventional single line statement like one of the following:

[cc lang="ruby"]
# C-like syntax
if ( expr ) {
put s;
}
if ( expr ) put s;

# Pascal-like syntax
if expr then begin # could use 'do' instead of 'begin'
put s;
end;
if expr then put s;

# Python syntax is best
if expr:
put s
if expr: put s
[/cc]

Function Pointers or Function Objects

Ruby really messed up with function pointers (or function objects):

Ruby
[cc lang="ruby"]
# What planet did this come from?
def func(list)
for i in list
yield i
end
end
func(['cat','dog','horse']) do |animal|
puts animal
end
[/cc]

Python
[cc lang="python"]
# This is from earth
def doSomething(i):
print i

def func(list,function):
for i in list:
function(i)

# Python does not yet have multi-line anonymous
# functions. The lambda functions in Python are weak.
func(['cat','dog','horse'],doSomething)
[/cc]

Ruby
[cc lang="ruby"]
# This is better
def func2(list,function)
for i in list
function.call(i)
end
end
func2(['cat','dog','horse'],
# proc(animal) is a better choice
# delegate(animal) is like C#
proc do |animal|
puts animal
end
)
[/cc]

The first Ruby example uses syntax which none of us should ever have to learn. To make matters worse, the keyword “yield” is used which means something totally different in C# and Python. I haven’t yet found a way to pass a predefined function as an argument to a Ruby function. Ruby does support passing method pointers using the “method” feature (ex “variable.method(:methodName)”), but again Python provides a much simpler syntax. To pass a method pointer in Python you just specify “variable.methodName” like you would in C#.

Ruby’s grammar is riddled with multiple ways of doing things. Adding to the confusion, it often unnecessarily chooses syntax different from popular languages we are familiar with. As a result, Ruby is much more difficult to learn, read, and write.

Not everything is better in Python. For example, Ruby’s class/member syntax is better than Python. For me, this doesn’t help Ruby nearly enough to make it a better language.

Summary

Both Ruby and Perl have large ambiguous grammars (Perl’s grammar is worse). They often disambiguate syntax based on context. For example, the slash symbol (/) can mean divide or perform a search depending on the context. In the search case, the slash is used to delimit the string. This is an unnecessary complexity since this is just another way to call a function with string parameters.

There will never be a case where having a very large and ambiguous grammar makes a language better. This is one of the flaws in C++. I’m an excellent C++ programmer and I’ve had to stare at some C++ statements for way too long. Note that Java and C# have very small unambiguous grammars with only a few shorthands. Modern languages have so many features that they must keep the grammar small in order to reduce the learning curve. I guarantee that the best state-of-the-art languages of the future will do the same. For this reason alone, Python is clearly better than Ruby or Perl. Keep in mind that I have not compared the run-times of these languages and there are often cases where you end up choosing a language due to its run-time features.

There are other ways that scripting languages can speed the programming process without creating a large grammar with excessive shorthands. For example, unqualifying names with import/using statements and choosing short name space names for standard run-times (Python does both of these). Also, if the grammar is small and unambiguous, editing tools like SlickEdit can provide more assistance.

My next article “A Deeper Look at Python”, will talk more about Python and what things make a language state-of-the-art.