[<<] Industrie Toulouse

A couple of years ago, while still working for Zope Corporation, I started to take a look at a programming language called Ruby. Ruby is an interesting language, and is best described as a mixture of Smalltalk and Perl. From Smalltalk, Ruby inherits a "pure" object oriented design, with a single class hierarchy and the notion that everything is an object/method. Even what some would consider as linguistic keywords are methods of the Kernel class/object. Unlike Smalltalk, however, Ruby uses more traditional imperative programming constructs, whereas Smalltalk does everything in message passing syntax. From Perl, Ruby picks up a lot of Unix shell programming features, first class regular expressions, all the joys of $_, $?, $:, and more. It also seems to have picked up the There's More Than One Way To Do It mentality of Perl as well, with a few different ways of spelling blocks, loops, and more. In Python, two people can enter the same algorithm and yield very similar looking code. In Ruby, two people can enter the same algorithm and yield radically different looking code, depending on how they like to spell certain things, whether they put their ifs at the beginning or end of the line, ie - next if a = b or if a = b then next. In Python, there's only one way to do it, if a == b: continue. Use of the return statement in Ruby is optional. If it's not used, the last value in the method is returned. Looking at the following code, I have no real clue as to what's being returned here (besides the possibility of 'nil'). With some hard looking, I can figure it out. I imagine that once one becomes familiar with Ruby, this would be understandable.

  def []( key )
    @table[key] or return nil
    @table[key].gsub(%r<\$([^/]+)>) { self[$1] }
It's definitely not executable pseudocode (even without that regular expression in there), which is a rather common description of Python.

So while Ruby's influences are primarily Smalltalk and Perl, Python's influences include the ABC teaching language, Icon, Algol-68, and Modula-3. This is definitely where the import statement came from. Modules are my favorite feature about Python, especially after taking quick looks lately at Perl, Ruby, and PHP - all of which use multiple statements to load source code from one place into another. There is something inherently graceful and simple about Python's module system. A module is any Python file. Any named objects inside of that module are usable outside of it. They're accessed through dot notation.

  import foo

  def rebar():
    b = foo.bar()
    return b * b
Ruby, and some other languages, come up with yet-another-notation to access things inside of their modular namespaces, such as the double colon (which may then sometimes get used with dot notation as well).
  require 'foo'

  def rebar
    b = Foo::Bar.bar
    b * b
Ruby also uses single (or double) prefix characters on names to excess, with a difference between name, $name, @name, @@name. The prefix characters denote scope, with @name being analogous to Python's self.name - looking up an instance attribute. There are other clever little prefixes used, such as colons, to do other operations. This creates a language full of cryptic single character command shortcuts, when in fact - none of them need to be used. Python, on the other hand, uses no such prefixes. The only characters heavily used in Python are the dot (object/module/etc traversal), and the leading underscore (sometimes overused), usually used to protect names or highlight special 'slots'. Ruby has a lot of cute and clever elements, and it really is a pretty good language. But it really makes me appreciate the zen simplicity of Python, wherein "explicit is better than implicit" and "there should be only one way to do it" are common mantras:
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
(execute import this in a Python interpreter, and this is what comes up).

I think that there's just a lot to appreciate about Python. It's not a perfect language, but it's getting better all the time. I staked my professional life on it in early 1997 and haven't had to look back since. I do like to stop and experiment with other programming languages on occasion, and you can read about my experiences with Ruby here. Interestingly, most of the really major things I liked about Ruby found their way into Python 2.2. Sitting down with another programming language for a while can open your mind up to other ways of solving problems, and I think I became a better Python programmer after spending time in Ruby land. It certainly made me better prepared for the new features that Python 2.2 sprouted.

I do think that Ruby is a cool language and it still has some pretty nice features that differentiate it from other languages in its field. But aside from some small shell scripts, I don't expect I'll ever do anything major in it. Most of my world is in Python right now. And when it comes time to sit down and figure out a new programming language, I really want to wrap my brain around Haskell in order to appreciate a really different way of doing things.

p.s. Speaking of early 1997 - the February 1997 issue of Byte had one of the first major magazine articles about Python, written by yours truely. :)

p.p.s., Andrew Kuchling wrote an excellent letter to Salon. One quote from it is this:

There are languages that are more compact than Python -- Lisp treats everything as a list, while APL used arrays everywhere and Tcl used to use strings -- but it's possible to go too far toward minimalism. People have different preferences, and I like Python's simplicity/complexity tradeoff, midway between Lisp's simplicity and Perl's complexity. Other people will find a different level of comfort.
Ruby and Smalltalk's system of pure object/messages are another degree of linguistic simplicity, on or near the level as Lisp. But while Ruby does employ a more imperative structure than Smalltalk, this still contributes to some funny looking syntax. In the next paragraph, Andrew mentions Modula 3's design goals:
his idea of simplicity may have come from Python's Modula-3 influence; if you read the introduction to the Modula-3 language definition at http://www.research.compaq.com/SRC/m3defn/html/intro.html, you'll see that the designers of Modula-3 limited themselves to a specification that could be printed in 50 pages. Python is similarly simple; almost all of the language's features can be explained in tens of pages, and suggestions for new features are often rejected because they'd complicate something too much.
All I can say is - I'm glad the Python community rejected PEP 308 (ternary operators for Python), especially after seeing this bit of Ruby code:
  x = if a<0 then b else c
That just doesn't read right. One of the proposed syntaxes in PEP 308 was to make it like this in Python:
  x = b if a < 0 else c
which reads a bit more easily... but only a bit. Again - I'm glad this whole thing was rejected, and by the community at large.