Ian Bicking: the old part of his blog

Ruby, Python, "Power"

There are different opinions on the relative power of Ruby and Python. I'm not much more authoritative than other resources (though I'm not less authoritative either; most comparisons between the two languages are flawed). Ultimately I don't believe there are many (any?) places where one language is more "powerful" than the other (and not just in the "they are both Turing complete" sense).

This was originally written August 2005. I'm a Python programmer, feel free to infer bias. At the same time, I don't know enough about Ruby to make many negative assertions (to identify something that Ruby is missing) -- I know what is in Python, but I don't know enough about Ruby to claim an equivalent doesn't exist there. As a result this post probably seems rather defensive of Python, because I do know enough to correct some of the inaccuracies about Python that I've seen in many other comparisons. Corrections or opinions? Comment below.

Contents

Ruby Blocks

Ruby blocks usually the first topic when judging the two languages. Syntactically Ruby is better in this respect; Python's functions are not as convenient as Ruby's blocks, though they are mostly equivalent in functionality.

This is trully annoying for the Twisted people, who have to write things in reverse because of it -- this is because Twisted (and asynchronous event-driven programming in general) does things like do_this(when_you_are_done_do=next_step), where the do_this function calls next_step() when it finishes. In Python next_step has to be a function, and (ignoring the syntactically awkward lambda) the function will have to be defined before you make that call. So even though do_this is called first, then next_step called after, you have to define next_step before you use it.

However, outside of asynchronous code -- which uses this callback style very heavily -- this is not a big problem in Python. Many places where Ruby uses blocks, Python uses for loops, and it is not syntactically any worse for it; Python's iterators and generators are every bit as general as Ruby's collection interface. In other cases where callbacks are used Python doesn't feel nearly so awkward. For instance, consider the atexit, module where you register callbacks to be called when the process quits:

def close_db_resources(): ...

atexit.register(close_db_resources)

There's nothing wrong with that: naming the function is not onerous; defining it before it is passed to atexist.register is not backwards.

Another case where Ruby uses blocks is resource finalization, where in Python you currently use try:finally: (using functions and callbacks is almost never done for finalization in Python, simply because it is too awkward). Ruby isn't particular more powerful in this way, but it does make it easier to do the Right Thing (cleanup properly), where Python makes it easier to do the Wrong Thing (forget to cleanup). Python is addressing this with PEP 343. Ruby was part of the motivation for the semantics and syntax of PEP 343, though ultimately the result isn't that similar.

Closures

Long ago Python functions were not "closures", in that they did not have access to the variables defined in enclosing scopes. That hasn't been true for several years, though it is still frequently seen in comparisons.

Threads

Sometimes Python and Ruby are considered equivalent here. They are not. Ruby, to my knowledge, does not support OS (preemptive) threads, or if it does it is buggy (or "experimental") and most code is not threadsafe.

Ruby does have non-OS threads, which are not preemptive. These are like Stackless' microthreads. Unfortunately Stackless is a dead-end at this time, and microthreads are not available in mainstream Python. PEP 342 addresses some of the use-cases for microthreads (and in the process some of the issues with Twisted-style callbacks, I think). I don't know if microthreads are used to any great effect in Ruby.

Python does support preemptive OS threads. Because of the GIL (Global Interpreter Lock), processor-bound Python applications cannot make use of multiple processors by using threads. This is sometimes seen as being equivalent to Ruby's thread situation: it is not. The GIL detracts from one feature of threads: utilization of multiple CPUs. It is still very viable to use threads to handle concurrency in Python. Ruby threads also do not block on I/O, though other C extensions often will block.

Python OS-level threads can be used to handle concurrency well when some threads are blocking on external sources (disk access, network IO, waiting on a socket, etc). Multiple processes can be used to the same effect in both languages.

Microthreads can be used for massive concurrency (thousands of independent contexts of execution). In Python this can be accomplished with generators (somewhat awkwardly) or in the future with coroutines (less awkwardly).

Continuations

Ruby supports continuations. Python does not (except in Stackless again). Continuations are not widely used in real applications in either world, but they do open up the possibility for things like Borges (how exactly CherryFlow works in the absence of Stackless I'm not sure). One notable use of continuations in Ruby is for breakpoints in debuggers.

Unicode

Python has native Unicode objects, with very full support for everything Unicode implies. Ruby does not have Unicode objects, only the ability to translate encodings, storing all strings as bytes. From what I can tell the translation (iconv) relies on operating system libraries. I expect this leads to significant portability concerns, though I don't really know.

Metaprogramming

Both Python and Ruby have strong support for metaprogramming. This is a major differentiation from language like PHP, which though also a dynamically typed language does not have many metaprogramming abilities (short of code generation).

Many of Rails' most-touted features use metaprogramming. In a general sense all of these things can be achieved in Python, though the techniques are usually quite different.

In both languages you can run code on a class when it is created. In Python this requires specific recipes implemented in the metaclass, which I believe has kept people from using this technique more often.

In Ruby I believe you can call class methods as part of the class definition; these methods effect class definition. Things as basic as getters and setters are implemented using this. In Python the class doesn't exist until the class statement has been fully evaluated, so you can't do this; instead the metaclass has to act on the class based on attributes you defined. Things like PyProtocol's advise() function simulate the Ruby process, but only with great effort.

More common in Python is metaprogramming through decorators or descriptors. I don't know what other techniques Ruby has.

I get the impression that a lot of Ruby's metaprogramming is done through runtime source generation and eval (at least in Rails). This is possible in Python, but uncommon. I think this is mostly cultural, though things like whitespace sensitivity in Python are non-starters for code generation. Many Python programmers (myself included) look down on code generation, adding to this cultural disinclination.

Object Oriented Programming

Sometimes Ruby is called "more OO" than Python. I don't think this has much basis.

Both languages are better understood as message-passing than class-based OO. That is, instead of being focused on types and classes, you have "objects" and you ask those objects for things. Classes are an implementation detail. This is a typical feature of dynamically typed systems, and an important basis for metaprogramming.

What you ask objects for is different in the two languages. In Ruby you ask objects to do something. There are no exposed attributes, just methods. Some Python programmers get in a tizzy because functions are not first-class in Ruby (there is no functions, just messages called "methods"). This isn't really fair -- the basic concept (deferred execution) is present in the form of blocks.

In Python you ask an object for attributes, and those attributes may be bound functions. Though the perspectives are different, the functionality is ultimately the same.

Both languages allow you to subclass built-in classes as well as user-defined classes. Very old comparisons criticize Python because this was not possible at one time (pre-2.0). However, from a message-passing perspective it's not an important feature anyway -- focusing on types and inheritance is an implementation concern. Also, built-in types have always been objects in Python. They are not special values like Java's ints, there is no "boxing" and "unboxing" nonsense. Objects should not be confused with types or subclassing. In both languages everything is an object.

Magic Methods

Many idioms in Python are achieved with algorithmic protocols instead of relying strictly on methods. For instance, len() is a function which calls a specific protocol:

  • See if the object has a __len__ method. If so, call that and return the value.
  • Otherwise raise a TypeError.

Other protocols are significantly more complex. bool():

  • Check for specific false objects: None, 0.
  • See if the object has a __nonzero__ method. If so, use the return value of that method.
  • See if the object has a __len__ method; use that next (zero-length objects are false).
  • Return True (anything that isn't false is true).

Some people really dislike the __method__ attributes. I think this is mostly an aesthetic concern, and aesthetic concerns do not relate to the "power" of a language, hence their absense from this essay.

Fundamentally the "root" Python object is nearly empty; it defines nothing and does nothing. It didn't even have a name in the past (now it is object). In Ruby there is a base object Object, which has lots of methods, and those methods embody these protocols. Python uses functions to the same effect.

While there is a uniformity to Ruby's technique, Python's technique also has some advantages. One is that functions are isolated and contained in a namespace; methods/attributes in Ruby and Python do not. Python's magic methods don't have a namespace, but in practice they are less likely to clash with other methods because of the distinction between "magic" and "not-magic".

Also, Python's use of functions that optionally call magic methods makes it easier to add backward-compatible functionality. For instance, at one time comparisons (like a<b) only called __cmp__ method (which returns -1,0,1); now they call a more specific method (like __lt__ for less-than) and fall back on __cmp__. This has happened many times over the life of Python, but you'll only notice that when you start defining your own magic methods.

Ruby has some ability to modify objects in ways Python doesn't (Python makes many objects and classes immutable by convention and implementation). For instance, you cannot add methods to Python's object or str (string type). Any clever uses of the ability to modify base types in Ruby are, I think, misguided; Python's immutable base types mean that there are fundamental abstractions and capabilities that all Python users and libraries can rely upon. Anything else is handled with functions and protocols, which are much more isolated. Modifying fundamental types makes interoperability very hard. Of course, no one is forcing you to do that in Ruby, so wise programmers can avoid such things.

Mix-Ins

You can do these in Python just like in Ruby -- classes can be easily modified after they were defined. In Python you can also use multiple-inheritance. For some reason people don't do either that often in Python. I think it's mostly cultural.

Python could be seen as more powerful because of multiple inheritance. But I think inheritance isn't that important anyway, so it's not a feature I would put much weight in. Mutliple inheritance is mostly distinct from mix-ins in that it is resolved at call-time, where mix-ins are resolved at class-definition-time. Which is better? I don't really care.

Restricted Execution

Ruby has tainted strings with various associated settings for running code in a restricted environment. Python had the rexec module, but it was insecure and removed some time ago. No one is working on a Python replacement.

Performance & Environment

Ruby and CPython (CPython being the name of the "normal" Python implementation) perform roughly the same. Ruby itself does not have a virtual machine, acting instead as an interpreter (the YARV project intends to add a VM to Ruby). At the same time, the Python VM is nothing very special -- while certain routines have been heavily optimized (like hash tables and the sorting algorithm) the VM itself is unexceptional. Benchmarking is hard and unrewarding, but perhaps this is an interesting comparison.

Ongoing work is very active in both languages. Notable Python projects:

Many Ruby equivalents exist:

I would love if Parrot created an environment where Python, Ruby, Perl, PHP, and other open source languages happily coexisted and shared a basic infrastructure. It doesn't have to mean 100% transparency between languages for it to be useful and successful. But at this point it's hard for me to believe Parrot will catch up to other competing runtime environments.

Libraries

For both languages the libraries are very important to their utility. It's difficult to list all the differences, but in most (nearly all?) areas Python has more complete library support, in terms of pure functionality. At the same time, Perl is probably better than either; but you only need Good Enough libraries for your application. Ruby may provide that, depending on your application. And no system provides the perfect libraries for everything, so it is always a tradeoff.

What's better in Python?

There are a few libraries that I think are notable for Python, because they address core programming techniques; things that might be language extensions in other, less dynamic languages. They are also notable because they aren't part of the Python core, for better or worse. In many cases Ruby equivalents exist, but may not be as mature (most of the reference projects have been in development in Python for many years).

  • Formal interfaces (Zope and PyProtocols); both also include the adaptation of objects. Ruby work on the same ideas is happening in ruby-contract
  • Generic functions (another take on the issues of adaptation)
  • Pyrex and ctypes for integration with external libraries (both languages support SWIG well)
  • py2exe and py2app for distribution of complete applications (both languages are ameniable to normal distribution methods on Unixy systems). Ruby modules to do the same sorts of things is happening in rubyscript2exe and Exerb
  • Numarray and scipy for dealing efficiently with large (typically homogeneous) datasets. Ruby work on this is happening in sciruby and Numerical Ruby
  • Psyco for various runtime optimizations (note that there is lots of ongoing performance-related work in both languages; Psyco is notable because it is very usable right now)

What's better in Ruby?

I'm not that familiar with Ruby libraries, but I get the impression that like Python the Next Step for Ruby will be accomplished on top of the language, not as an extension to it. If you know of something that belongs here, please comment. (Note: I'm not including tool-like libraries or application frameworks in these lists -- that way lies aesthetics; a valid thing to argue over, but not here please.)

  • gems for packaging of libraries (setuptools is trying to address this issue in Python). distutils is a little more self-contained for compiling C code.
  • rdoc is their standard documentation extractor/generator. Python has these, but no real accepted default generator.
Created 17 Aug '05
Modified 30 Aug '05

Comments:

There's a lot of content in this article, some of which I'm not 100% sure about. I'll try to fold in any corrections provided, and note the updates in this comment.

2005-08-17: Updated per Seo Sanghyeon's comments to note Ruby's Safe, distutils C compilation, and Ruby's rdoc. I'll probably put some of his other comments into a "VM" section.

2005-08-21: Updated per Florian Gross's comments: Ruby threads are preemptive for I/O; utility of continuations for breakpoints; source code generation might just be common in Rails; that Psyco is not alone in concept, but alone in terms of maturity.. Noted projects: ruby-contract, rubyscript2exe, Exerb, Ruby Numeric alternatives.

Changed some of the finalization commentary in Ruby Blocks; PEP 348 and Ruby blocks are more similar than I originally realized when I first wrote this. Added section on "Performance & Environment". Also added table of contents.

Added link to benchmark in aforementioned section.

2005-08-29: Added a note to the intro, that my asymmetric knowledge of the two languages can actually lead to a pro-Ruby bias to the comparison. Fixed commenting.

# Ian Bicking

I would like to comments three points.

First, about threads, the use of Python GIL makes OS threads not that different from Stackless threads. Let say that if you deal only with Python code there won't be any differences at all as in both case it is the Python interpreter who decides when a context switch will occure (in one case byu releasing the GIL, in the other by actually switching the current thread). There are two situations where you'll see some differences. First, if you use some extension library performing long tasks without accessing any Python function, it can release the GIL, allowing a true multi-threading, even multi-processor computation. Second, if you have to interface Python with some other library (like, say, Qt) you can use Qt threads and, along with that, Qt cross-thread message system.

Second, about multiple inheritance. Python syntax does allow for multiple inheritance and it does work with pure-Python objects. However, it does not work (in CPython) with built-in objects (try deriving from both str and dict). As Python's main force is the possibility to extend it with efficient languages and that you can seemingly replace a full-Python object with a built-in object, probably as a required optimisation, multiple inheritance is bad practice as it would forbid you to replace a full-Python object with an extended one. Until CPython resolve this problem, I will consider Python not being able to handle multiple inheritance.

At last, about OO. Just to say that I really don't care if a language is 100% OO, whatever that might mean. The main reason is: no two person has the same feeling about what "100% OO" is ! Another is: if the language is efficient and "just work", who cares if it's 100% OO or 0% OO or whatever ??? Nevertheless, I agree with your comments about OO and Python, I found it very interesting !

# Harbort

There are two situations where you'll see some differences. First, if you use some extension library performing long tasks without accessing any Python function, it can release the GIL, allowing a true multi-threading.

Do you realize that "Some extension library" includes any file operation, any socket operation, and in general, any blocking system calls? CPython's fileobject.c and socketmodule.c is full of Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS to enable this.

# Seo Sanghyeon

At last, about OO. Just to say that I really don't care if a language is 100% OO, whatever that might mean.

I care a lot. For instance, if Python classes were not objects (but syntactic constructs or something, like in Java) that would be awful. If I had to worry about boxing, that would be awful. If Python isn't 100% class based, no problem. Smart OO programmers know that OO is not the same thing as classes. Python is 100% object based, and that's really really important. IMHO, that makes it substantially more OO than Java.

# Ian Bicking

Well, my point was more about: what does it add to get the "100% OO" label ? IMHO, nothing ! Even more: "100% OO" might means (and apparently mean) different things to different people.

I really don't care about the label ! But I do care about the language coherency ... In Python everything you manipulate is seen as object (at least syntacticaly) and that's enough for me. But if someone feels it is not enough to be "100% OO", well, he might be right, but I don't care ! That's all I wanted to say ...

# anonymous

Ruby is 102% OO then.

# anonymous

Examples please?

# Mark

http://www.insula.cz/dali/material/rubycl/RubyIOClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyExceptionClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyDataClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyCoreClasses.jpg

The entire language was built from the ground up using OOP concepts. IMHO that makes it more oop than just about anything else. Every aspect of the language can be manipulated including the object "Class" which can be manipulated on the fly as it's created.

It makes the language very easy to learn because so much of the language is polymorphic. Got a file handle, try the put method. Got a standard out handle, try the put method. Got a network socket, try the put method. . . . you get the idea. Working with ruby I feel like I need less of a reference than other languages. Once I get used to a particular class hierarchy I understand that most of the inherited methods are available for all classes in that tree.

I had a python stint and really liked the language, but feel that Ruby code is more expressive. I know that is cosmetic or semmantic which you seem to be trying to avoid. I think if I were defending python I would avoid them as well. :) In all seriousness tho, python is great . . . ruby is great. It's all about enjoying what you do and if python makes you happier than ruby then that's what you should do.


http://www.insula.cz/dali/material/rubycl/RubyIOClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyExceptionClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyDataClasses.jpg http://www.insula.cz/dali/material/rubycl/RubyCoreClasses.jpg

The entire language was built from the ground up using OOP concepts. IMHO that makes it more oop than just about anything else. Every aspect of the language can be manipulated including the object "Class" which can be manipulated on the fly as it's created.

It makes the language very easy to learn because so much of the language is polymorphic. Got a file handle, try the put method. Got a standard out handle, try the put method. Got a network socket, try the put method. . . . you get the idea. Working with ruby I feel like I need less of a reference than other languages. Once I get used to a particular class hierarchy I understand that most of the inherited methods are available for all classes in that tree.

I had a python stint and really liked the language, but feel that Ruby code is more expressive. I know that is cosmetic or semmantic which you seem to be trying to avoid. I think if I were defending python I would avoid them as well. :) In all seriousness tho, python is great . . . ruby is great. It's all about enjoying what you do and if python makes you happier than ruby then that's what you should do.


"(how exactly CherryFlow works in the absence of Stackless I'm not sure)"

basically it doesn't. without Stackless or Statesaver, the back and reload buttons don't work on a CherryFlow app.

# anders

Great article. Following is my suggestions for additions:

# Seo Sanghyeon

wait, do you like ipython or not? You say it "completely blows" but then imply that it's better than both the python shell and the ruby shell?

# Bill Mill

I think "completely blows" is mangled idiom intended to mean "completely blows away" or "is vastly superior", which iPython really is.

# David S.

As far as I know, Ruby works by evaluating AST (like Perl). No bytecode, i.e. pyc. This has speed implications.

Being addressed with YARV. I think this is one of the factors that don't actually make much of a difference.

Different GC approach (refcounting and mark-and-sweep) and its implication to C extensions need to be mentioned. Debunk "Python lacks real GC" myth. (Cyclic GC was there... since 2.0!)

Agreed, writing Ruby extensions is a lot easier than writing Python ones. This comes with a downside of course: Ruby's conservative GC isn't guaranteed to collect all objects. (There might be things on the stack which look like object references, but aren't.)

There's plans for having a generational GC in Ruby 2. This ought to help quite a bit with performance if done right.

Jython and IronPython need to be mentioned. I don't know much about JRuby.

JRuby seems stable. It's being used in jEdit for making a lot of magic work magically. Pretty cool stuff. There's a lot of Ruby.NET implementations and I'm working on one of them (getting sponsored by Google's Summer of Code) -- you can eventually expect a break through in that area, but it might still take some time.

Compare to Perl's taint mode.

ruby -T is exactly that. :)

Python includes parser module and compiler package to deal with Python sources. Ruby didn't, last time I checked. Also compare Perl's downright horrible B module -- but at least it's there.

Ruby comes with Ripper in the development branch AFAIK. That's a good way of parsing Ruby source code. There isn't an established and sexy parser framework just yet.

Get IPython which completely blows. One may stil argue irb is a part of core distribution and IPython is not.

Any features that IRB doesn't have?

Distutils. No, gem doesn't count, it is a package manager. (Contrast PHP's PEAR vs. PECL.) For building C extensions, I think distutils got many things right compared to Ruby's mkmf or Perl's MakeMaker, the most important being independence from Makefile. I am not up-to-date on Ruby/Perl for this. Corrections welcome.

Not too experienced here, but it can probably be solved with a custom Rakefile. See http://rake.rubyforge.org/

# Florian Gross

Perl uses bytecode too, actually.

# Alex

> It is still very viable to use threads to handle concurrency in Python.

Sorry, no, it isn't, neither in Python, nor in Java, nor in most languages.

> Many Python programmers (myself included) look down on code generation

Many Twisted programmers (myself included) look down on threads.

It's multiprocessing, or asynchronous events, or both.

Repeat with me:

"There are no threads. There are no threads. There are no threads."

;-D

# Nicola Larosa

Another thing I see a lot from Java and Ruby people is, "explicit self sucks!" Hans Nowak has written about this at length from a Python perspective so I usually point people to his site.

http://zephyrfalcon.org/weblog/arch_d7_2003_07_12.html#e283 http://zephyrfalcon.org/weblog/arch_d7_2003_07_26.html#e298 http://zephyrfalcon.org/weblog2/arch_e10_00770.html#e776

# Jonathan Ellis

Python will probably never get "Ruby blocks" or continuations or full-featured AST manipulation. Guido avoids these very powerful and very general solutions. Guido would rather give a few 20% solutions that cover 80% of the use cases. Iterators and generators are good examples of this. They are only 20% as powerful and general as blocks and continuations, but they cover 80% of the "real-live" use cases.

Also, Python strives for readability. I feel the existance and popularity of Ruby has been a net positive for Python, because it keeps programmers who don't greatly value readability away from our Python codebases.

# AnIdiot

Also, Python strives for readability. I feel the existance and popularity of Ruby has been a net positive for Python, because it keeps programmers who don't greatly value readability away from our Python codebases.

Ruby also wants to be readable, but doesn't enforce this by limiting the language. I will agree that Perl style variables are ugly, but well written Ruby code is just as pretty as Python one IMHO.

# Florian Gross

I'd go further than this. "Readability" has as much to do with symmetrical constructs as it does algolishness. I don't believe that it's a larger hurdle for an algol-family programmer to grok blocks than it is for them to grok list comprehensions or lambdas. And I think it's a smaller hurdle for them to grok blocks than it is for them to grok both list comprehensions and lambdas.

Ruby readability is also greatly enhanced by its perl heritage. The lack of =~ and similar is what prevent python from succeeding perl years ago. You may call these things sugar, but these are all Turing compatible languages so at the end of the day it's all sugar.

# Peter Merel

I love when people talk about turing compliance ;). The argument that any languages that are Turing compliant must be equivalent is IMO very misunderstood, by this reasoning there is no difference between any two languages (besides syntax). This simply isn't true, take for example C++ and Java, both are Turing compliant and both are OO, however there's a big difference in what you can do with them.

Another example? How about Lisp and Java, both are Turing compliant yet the list of things Java can't do is longer than my arm, one example being closures. Taking this into account obviously not all languages are equal so I would love very much for people to stop throwing Turing compliance about in this way :).

Last one, how about Python and Lisp. I read above that Python has full support for lexical closures now however I'd like to point out that this isn't exactly true as Paul Graham pointed out in the article below.

As an illustration of what I mean about the relative power of programming languages, consider the following problem. We want to write a function that generates accumulators-- a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. ... In Common Lisp this would be (defun foo (n)

System Message: ERROR/3 (<string>, line 12)

Unexpected indentation.
(lambda (i) (incf n i)))

System Message: WARNING/2 (<string>, line 13)

Block quote ends without a blank line; unexpected unindent.

... If you try to translate the Lisp/Perl/Smalltalk/Javascript code into Python you run into some limitations. Because Python doesn't fully support lexical variables, you have to create a data structure to hold the value of n. And although Python does have a function data type, there is no literal representation for one (unless the body is only a single expression) so you need to create a named function to return. This is what you end up with: def foo(n):

System Message: ERROR/3 (<string>, line 16)

Unexpected indentation.

s = [n] def bar(i):

System Message: ERROR/3 (<string>, line 18)

Unexpected indentation.
s[0] += i return s[0]

System Message: WARNING/2 (<string>, line 20)

Block quote ends without a blank line; unexpected unindent.

return bar

System Message: WARNING/2 (<string>, line 21)

Block quote ends without a blank line; unexpected unindent.

Python users might legitimately ask why they can't just write def foo(n):

System Message: ERROR/3 (<string>, line 23)

Unexpected indentation.
return lambda i: return n += i

System Message: WARNING/2 (<string>, line 24)

Block quote ends without a blank line; unexpected unindent.

or even def foo(n):

System Message: ERROR/3 (<string>, line 26)

Unexpected indentation.
lambda i: n += i

System Message: WARNING/2 (<string>, line 27)

Block quote ends without a blank line; unexpected unindent.

and my guess is that they probably will, one day. (But if they don't want to wait for Python to evolve the rest of the way into Lisp, they could always just...)

http://www.paulgraham.com/pypar.html

Arguing over which is the most OOP language is somewhat silly in itself :). OOP is not an abstraction that suits every task and yet it's used everywhere now – with varying results of course. I've read a lot of code written using OO and it instantly occurs to me that the same task could be accomplished with less work and while maintaining the same amount of modularity WITHOUT all the extra work of writing classes for types and defining methods, attributes etc.

OOP is good for some things and truly horrible for others – I wish the world would realize this. All in all though they're both good languages, personally I like Ruby more. I used Python for 4 years [think it was my 4th or 5th language] and by the end just found it way to restricting to bear :).

If you haven't already you should learn both, hell you should probably learn every language that crosses your path anyway but still. Learn Ruby if your a Python user, learn Python if your a Ruby user and then you'll be better equipped to judge both languages. That and you'll learn useful concepts that may carry over?

Enjoy guys,

Mark.

# Mark Smith

Umm... What?

Python 2.3.5 (#2, Nov 20 2005, 16:40:50)
>>> def f(n):
...     return lambda x: n + x
...
>>> inc5 = f(5)
>>> inc5(10)
15
>>>

In which way isn't that lexical closure?

Oh, you mean the fact . Of course it does, but it doesn't matter.that ints are immutable in Python? Or the fact that names are just that in Python: names for objects, rather than references to slots?

That doesn't have anything to do with closure. It's just the way assignments work in Python.

Lisp requires you to declare names, distinguishing assignment from binding. Python doesn't. Is Lisp's way of doing things different? Yes, it is. Is it better? I don't think so.

Why do I think so? Your example is clearly much more elegant in Lisp than it is in Python, after all. But that's not the point. A Python programmer wouldn't use functions to represent incrementors: they would use objects (ignoring the fact that, up to now, I haven't needed an accumulator in my whole life, ever). In the context of object-orientation, Python's assignment behaviour makes a lot more sense than Lisp's. Stating that Lisp deals with functions more elegantly than Python does isn't a valid point, because it doesn't matter. It's like saying that a webcam isn't well suited for typing text: true, but not very interesting.

By the way, anonymous procedures will probably disappear from Python at some point anyway. If you really think that Python converges towards Lisp, you're probably wrong.


Oops... How did that happen?

s/. Of course it does, but it doesn't matter.//

I love when people talk about turing compliance ;). The argument that any languages that are Turing compliant must be equivalent is IMO very misunderstood, by this reasoning there is no difference between any two languages (besides syntax). This simply isn't true, take for example C++ and Java, both are Turing compliant and both are OO, however there's a big difference in what you can do with them.

I think you misunderstood Peter's post. He wasn't saying that all these languages are turing complete and, therefore, equal. In fact, he was implying the opposite of that!

Please read his post again...

He was implying that Pythonistas attack PERL's =~ operator by calling it syntactic sugar. He defended PERL by pointing out that the whole syntax of the language boils down to syntactic sugar in the face of Turing completeness. You see, he was using Turing completeness to compare the features of the language that we like to syntactic sugar to show that the =~ operator is more than just sugar. It is a legitimate feature of a language that gives it an advantage over languages that lack it. So, in the end, he's saying that Turing completeness doesn't make all languages equal...

# Id Kong

One thing about python is that it only evaluates variable bindings when the code is run. So it's quite possible to write something like:

def step1():
    do_something(next=step2)

def step2():
    do_something_else()

step1()

With the actual steps appearing in the right order in the code.

# Tom

I'd debate that modifications to base classes like Object or Class in Ruby are across the board misguided. Sometimes, being a clever little bugger is just what's called for.

As for Ruby libs: unit/test. Like manna from god damned heaven.

# Danno

Is there anything special about unit/test? We all have unit testing libraries; they are important, but I'm leaving out lots of important things that don't distinguish one language from the other.

Re: modification of base classes. I imagine modification of Object could be necessary at times. This is the flip side of Python's magic methods -- where you can build defaults and other rules into the function that then optionally calls magic methods, in Ruby (presumably?) you would create an implementation in Object that gets specialized as necessary. That's certainly the norm in Smalltalk, though I think there are some serious reason's to be concerned by how that effects the larger process and the many users of Object. From the opposite end CLOS handles the same thing with generic functions, with substantially better decoupling; in Python people are pushing in that direction with adaptation and generic functions, though that kind of development is not the form.

Along these lines, the experimental Javascript 2.0 spec adds namespaces to methods, mitigating the issues of adding methods to other classes. An interesting way to address the problem.

# Ian Bicking

Disclaimer: Read this post with the knowledge that I really only know enough about Ruby to be dangerous.

Hmm, no I don't think there's anything particularly standout about test/unit. I just really REALLY like unit testing and I think I didn't understand what you meant about notable libraries.

Oh, actually, now that I think about it, optparse is pretty sweet and I've never really seen anything like it other languages I've used (though I'm not really up on Python, so it may have something similar) RDoc here: http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/index.html

Back to Object mods: Well, you know, it's not too hard to do change localization in Object with the alias method. Like:

alias :meth, :old_meth

def meth
 ...
end

and then when you're done with being a clever bugger:

alias :old_meth, :meth and Bob's your Uncle, back to normal.

Not sure what you're talking about with CLOS and adaptation and generic functions or JavaScript 2.0 as I'm not up on that (in fact, I'm probablly not in a position to be talking about language features at all as it's certainly not my specialty).

I don't think popping Object open and changing it around is the flip side of Python Magic Methods though. Read the following section with the knowledge that I am no Ruby expert and know only of Python from mythical tales of its courage in battle:

From what I've used of Ruby, it would seem that the actual flip side of Python "magic methods" is just using some standard method names, like "to_s" or "each" that behave like they should for the Object they're inside of. I think the "magic" is typically accomplished with mixins, Enumerable being the example used in the Pickaxe where you define "each" to get a bunch of the iterators and "<=>" if you want the rest (I think defining "<=>" and including Enum also gives you Comparable, but you might need to add it explicitly) and then if you want a special version of one of the methods the mixin adds, you just go ahead and change it.

I'm gonna shut up now because if I keep talking, I'm probablly going to misrepresent something and start a flamewar.

# Danno

Oh, actually, now that I think about it, optparse is pretty sweet and I've never really seen anything like it other languages I've used (though I'm not really up on Python, so it may have something similar).

http://docs.python.org/lib/module-optparse.html -- need I say more? optparse existed in Python under name of Optik since 2001: http://optik.sourceforge.net/ and given apparent similarities in API, I even doubt whether Ruby one is clone of Python one...

# Seo Sanghyeon

I know neither Python nor Ruby at this point in my life, nor do I know PHP. I'm a pretty strong Perl programmer for general processing, although I've never built anything complicated, like a web application, in Perl. I have decided to learn Ruby, for two reasons:

  1. I also want to learn web application programming, and Ruby on Rails looks too good to pass up, and
  2. A couple of interesting applications in computer music, like gridflow, are Ruby-based.

I don't really look for "power" in a language. I look for code readability, a simple and stable core, and portability. I have to admit that I prefer "strong typing" and languages with compilers that prevent you from making lots of mistakes -- in that respect, I think Ada is king of the hill. I like the discipline to be built into the language and not supplied externally with processes and CASE tools. But I also realize that most programmers I need to work with won't touch a language like that with a ten-foot pole. The "new" languages -- Perl, Python, Ruby, PHP, etc. -- seem to be where the action is.

# M. Edward (Ed) Borasky

Ruby, to my knowledge, does not support OS (preemptive) threads, or if it does it is buggy (or "experimental") and most code is not threadsafe.

This is getting addressed in the Sydney project and might get merged back to Ruby (The YARV author wants to support native threads. YARV is the VM that will be merged with Ruby for 2.0). See http://blog.fallingsnow.net/articles/category/Sydney

Python OS-level threads can be used to handle concurrency well when some threads are blocking on external sources (disk access, network IO, waiting on a socket, etc).

This is usually also true for Ruby because it carefully uses non blocking constructs to implement IO.

Continuations are not widely used in real applications in either world, but they do open up the possibility for things like Borges (how exactly CherryFlow works in the absence of Stackless I'm not sure).

They might not be the most popular thing, but note that Rails comes with support for breakpoints which depends on continuations.

Python has native Unicode objects, with very full support for everything Unicode implies. Ruby does not have Unicode objects, only the ability to translate encodings, storing all strings as bytes. From what I can tell the translation (iconv) relies on operating system libraries. I expect this leads to significant portability concerns, though I don't really know.

Ruby has minimal Unicode support -- this only means that it is possible for Ruby to recognize UTF8 characters instead of treating them as their bytes. This is planned to get improved in Ruby 2.0.

In Ruby I believe you can call class methods as part of the class definition; these methods effect class definition. Oh, and note that I had trouble submitting this posting because my last name contains a German umlaut -- this is one of the things that usually work with Rails applications. :)

And note that in this case class methods are no exception. They are just methods defined on your class object (or one of its ancestors).

I get the impression that a lot of Ruby's metaprogramming is done through runtime source generation and eval. This is possible in Python, but uncommon.

I agree with you in that this is bad style. Ruby has the abilities that allow you to do dynamic things without introducing yourself to code injection and hard to debug errors. I'm not sure why DHH decided to go this way in Rails, but it is probably because it was started a while ago -- it could have been that eval() was just the fastest way of getting it to run. I think work is being done on replacing eval() by more specific constructs in Rails.

Some Python programmers get in a tizzy because functions are not first-class in Ruby (there is no functions, just messages called "methods").

In Ruby you can still do method = 1.method(:+); method.call(5) and it will do the right thing. But I understand that you were really talking about obj.foo being a method invocation instead of a property lookup. I've written a bit of code to emulate the Python behavior at http://flgr.0x42.net/method-dict.rb

Also, Python's use of functions that optionally call magic methods makes it easier to add backward-compatible functionality. For instance, at one time comparisons (like a<b) only called __cmp__ method (which returns -1,0,1); now they call a more specific method (like __lt__ for less-than) and fall back on __cmp__.

I'm not sure if I get this argument. In Ruby you can just override < by whatever you think is the best behavior or implement <=> (similar to __cmp__) and include Comparable and be done. There is no reason for the language to change the behavior of < so there won't be any backwards compatibility trouble either. If I'm missing something feel free to correct me.

I think this is mostly an aesthetic concern, and aesthetic concerns do not relate to the "power" of a language

This is not entirely true. Aesthetics will influence feature use. This is used to good effect in Ruby -- globals try to look ugly, for example.

Any clever uses of the ability to modify base types in Ruby are, I think, misguided; Python's immutable base types mean that there are fundamental abstractions and capabilities that all Python users and libraries can rely upon.

This is an important part of Ruby and one that gives a lot of power to the user. Want to read a File in chunks of N bytes? Add File#read_chunks_of() and you are ready to go. Think that there should be a way of detecting elements that appear multiple times in an Enumerable? Add Enumerable#find_collisions and you are done.

You are right in that the effect of open classes on stability has not been researched yet, but for Ruby it seems to work out fine so far -- good extensions get used a lot and spread. Bad ones are just ignored.

There has been talk of introducing selector namespace (which would allow for locally scoped modification of other classes) but it is not yet certain how that feature will be implemented and how it will work in detail.

Ruby has the Safe module for running code in a restricted environment.

Ah, this is built-in functionality, not a module.

Formal interfaces (Zope and PyProtocols); both also include the adaptation of objects

This is the very thing I tried exploring with http://ruby-contract.rubyforge.org/ which does typing via run-time unit testing. It also handles type adaption, method signatures and a few other features you would expect.

Pyrex and ctypes for integration with external libraries (both languages support SWIG well)

There's Ruby-DL which is part of Ruby's standard library. It allows you to wrap C libraries in Ruby in a very straight-forward way. This is also been (ab)used for http://rubyforge.org/projects/evil/ which uses Ruby-DL to get access to Ruby's internal object structure which allows it to implement multiple inheritance, obj.class= and similar things in pure Ruby. It has the name for good reasons, though.

py2exe and py2app for distribution of complete applications (both languages are ameniable to normal distribution methods on Unixy systems)

http://www.erikveen.dds.nl/rubyscript2exe/index.html and http://exerb.sourceforge.jp/index.en.html -- there is also various other utilities that do similar things. Some of them just gather all the source code into a single file, others convert .tgz archives into Ruby scripts etc.

Numarray and scipy for dealing efficiently with large (typically homogeneous) datasets

http://www.ir.isas.jaxa.jp/~masa/ruby/index-e.html and a lot more at http://sciruby.codeforpeople.com/sr.cgi/InterestingProjects

Psyco for various runtime optimizations

Hehe, Ruby's mostly still working on this. Keep an eye on http://rubyforge.org/projects/ruby2c/ and the YARV effort, however.

Anyway, I think it shows that you tried to give both languages a chance and the conclusion that the two languages are very similar and will become even more similar in the future is one I will agree with. Personally, I'm mostly using Ruby over Python because the language gives me control when I tell it that I really need it -- Python seems to be more of the "the one way we thought it" mindset. Let's hope that we can continue to steal lots of good ideas from each other in the future! Oh, and down with PHP while we're at it!

# Florian Gross

Hi Florian; I'll try to fold some of your comments back into the document, but a couple clarifications:

They [continuations] might not be the most popular thing, but note that Rails comes with support for breakpoints which depends on continuations.

This would probably be possible in Python with threads, where you halt the thread with the breakpoint, and spawn another thread to take over the response. The scalability issue isn't really a problem in this case (as it would be if you were using continuations for something other than debugging, as in Borges). Certainly easier to implement with continuations, though. As an aside, I've never actually liked breakpoints...

In Ruby you can still do method = 1.method(:+); method.call(5) and it will do the right thing. But I understand that you were really talking about obj.foo being a method invocation instead of a property lookup. I've written a bit of code to emulate the Python behavior at http://flgr.0x42.net/method-dict.rb

True; but I think it's important to still emphasize that the real equivalency isn't that Ruby can act kind of like Python, but that the same things can be accomplished with it. Of course, now that I look more closely at Ruby blocks, they don't act like I thought they did; they aren't really like Smalltalk blocks (unless you use lambda). Sigh... I guess I'm still unsure what the equivalent idiom is. (It took me a long time to figure it out, all considered; this document goes more deeply into blocks than the other things I found.)

I'm not sure if I get this argument. [about __cmp__ and __lt__ in Python]

This is a specific issue that came up with Python; in some ways it might be considered a flaw of Python's magic methods, because Python initially used the (seemingly) clever technique of using __cmp__ for all of < <= > >=. Later people wanted to distinguish between these operations. All objects didn't grow __lt__ methods (which in turn would call __cmp__), but instead the protocol (the series of methods that are tried) were put into Python (since the operators are a base part of Python).

But no particular case comes to mind where this kind of logic couldn't be put into methods of Object... of course, not in Python since there is no extensible base class.

This is an important part of Ruby and one that gives a lot of power to the user. Want to read a File in chunks of N bytes? Add File#read_chunks_of() and you are ready to go.

I accuse you of class-think! ;) I have lots of file-like objects that aren't files. A read_chunks_of(file) function will work great on any file-like object; File#read_chunks_of() will only work on actual File (or subclass) objects. Class-think breaks duck typing. Extending classes is also hard to keep track of; one of the most important aspects of Python namespaces is how reversable they are, so you can track where stuff comes from.

There has been talk of introducing selector namespace (which would allow for locally scoped modification of other classes) but it is not yet certain how that feature will be implemented and how it will work in detail.

People who consider these issues in Python are using adaptation now. I'm not entirely sold on adaptation, especially the extensive way Zope 3 is (ab)using it, but it does deal with that issue.

For instance, lets say you are making a CMS, and you want to add all sorts of methods to files that deal with workflow, parsing, etc -- you are using files as one of many basic content types. You could simply add those CMS content methods to the file class. But with adaptation you would make a wrapper that has the methods you want (and only the methods you want), and register the wrapper as handling things with the file interface. That means it will work with anything with the file interface (not just the file class), and other people can make other wrappers for other kinds of objects. And the whole thing is introspectable, and implies semantics in addition to signatures.

This way you don't get collisions, you get objects that really are what you want them to be (CMS content objects, not files posing as CMS content objects), but you also can use them as their "real" type (if you make sure to adapt them back to IFile).

I think adaptation makes sense. But I also see places where adaptation is being used as generic functions (multi-dispatch), and that's a kludge.

# Ian Bicking

This would probably be possible in Python with threads, where you halt the thread with the breakpoint, and spawn another thread to take over the response. The scalability issue isn't really a problem in this case (as it would be if you were using continuations for something other than debugging, as in Borges). Certainly easier to implement with continuations, though. As an aside, I've never actually liked breakpoints...

Oh, ruby-breakpoint uses continuations for implementing Binding.of_caller. This is necessary because a call to breakpoint() should spawn an IRB shell at the right point with the caller's context. It is quite involved and a very specific situation, but it shows that continuations can be useful even outside of traditional flow control. If you never actually liked breakpoints you should IMHO still have a look at this at http://ruby-breakpoint.rubyforge.org/ -- it is quite different to traditional stop and step debugging.

Of course, now that I look more closely at Ruby blocks, they don't act like I thought they did; they aren't really like Smalltalk blocks (unless you use lambda).

Lots of experiments with that as well. Ruby 1.9 did support variable = { puts 'Hello World!' }; variable() for a while, but I think that this really does belong more into languages that have method calls as field access plus call like Python and JavaScript. Not that I dislike it -- I think both models have interesting unique benefits.

I accuse you of class-think! ;) I have lots of file-like objects that aren't files. A read_chunks_of(file) function will work great on any file-like object; File#read_chunks_of() will only work on actual File (or subclass) objects. Class-think breaks duck typing. Extending classes is also hard to keep track of; one of the most important aspects of Python namespaces is how reversable they are, so you can track where stuff comes from.

Oh, sorry. This was my error. I should have said File.read_chunks_of which is similar to File.read -- in that case there is no trouble with reusability. You still raise a valid point, though, and perhaps MixIns should be used even more in Ruby when adding new functionality.

For instance, lets say you are making a CMS, and you want to add all sorts of methods to files that deal with workflow, parsing, etc -- you are using files as one of many basic content types. You could simply add those CMS content methods to the file class. But with adaptation you would make a wrapper that has the methods you want (and only the methods you want), and register the wrapper as handling things with the file interface. That means it will work with anything with the file interface (not just the file class), and other people can make other wrappers for other kinds of objects. And the whole thing is introspectable, and implies semantics in addition to signatures.

This way you don't get collisions, you get objects that really are what you want them to be (CMS content objects, not files posing as CMS content objects), but you also can use them as their "real" type (if you make sure to adapt them back to IFile).

Yup, this is similar to ruby-contract -- but still, I think that wrappers are not always the best solution to problems. If a good implementation of selector namespaces can be found I think it is besser for solving this specific problem. (Even though it has not been a serious problem so far. -- I guess it is part of the Ruby mindset that being tolerant is usually a good idea, even if it might mean that you can step onto others toes.)

# Florian Gross

[...] I think that this [bound methods] really does belong more into languages that have method calls as field access plus call like Python and JavaScript.

Incidentally Javascript doesn't really have this. It was most confusing to me as a Python programmer. Bob Ippolito described the situation well.

Yup, this is similar to ruby-contract -- but still, I think that wrappers are not always the best solution to problems. If a good implementation of selector namespaces can be found I think it is besser for solving this specific problem. (Even though it has not been a serious problem so far. -- I guess it is part of the Ruby mindset that being tolerant is usually a good idea, even if it might mean that you can step onto others toes.)

In practice most Python programmers get by just fine when they do stuff that risks name collision. Some people say it's just because the applications are small and reuse not that common; and it's people with an eye to big systems (like Zope 3 people) that are pushing for more isolation. I'm still not sure if it's easier just to deal with problems when they occur, instead of trying to avoid all possible conflicts. Especially in an open-source ecosystem -- when all code is open to change, and there is no "my code" and "not my code" -- I think problem-avoidance isn't as important as intelligent and cooperative problem-solving. And of course we both have the option to monkey patch (fix the code in-process, instead of on-disk).

# Ian Bicking

In my opinion Ruby is sexier but also more dangerous. My 2 year old python code is easier to understand and maintain than my 2 year old ruby code....

# culley

Since when can a programming language be sexy?

The readability of code has a lot to do with the author's grasp of the language as well. You can write nasty code with any language, but Java is one of the few system that enforces nasty structure:

Python:

for i in range(6000):
    x={}
    for j in range(1000):
        x[j]=i
        x[j]

Java:

import java.util.*;

public class test {
    public static void main(String[] args) {
        for (int i = 0; i < 6000; i++) {
            Map x = new HashMap();
            for (int j = 0; j < 1000; j++) {
                Integer I=new Integer(i);
                Integer J=new Integer(j);
                x.put(I,J);
                x.get(I);
            }
        }
    }
}
# Eric Radman

Java 5.0:

import java.util.*;

public class Test {
    public static void main(String... args) {
        for (int i = 0; i < 6000; i++) {
            Map<Integer,Integer> map = new HashMap<Integer,Integer>();
            for (int j = 0; j < 1000; j++) {
                map.put(i,j);
                map.get(i);
            }
        }
    }
}

But I'm not sure what you're getting at since this code doesn't actually do anything.

# Brian Slesinsky

Perhaps my post disproves my own point to some. I think the only thing I demonstrated was that it requires a lot more characters to write a program in Java that does nothing vs. a script in Python that does nothing. My problem is that I assume the virtue of Python code is self-evident, and it's not, because it's a matter of perspective. I suspect that Perl appears to be insane to most Java programmers, but it doesn't seem all that strange after writing a few things in Ruby.

# Eric Radman

source
Here's the ruby version, for completeness

6000.times do |i|
   x = Hash.new
   1000.times do |j|
      x[i]=j
      puts x[i] # Just to actually do something.
   end
end
# Joel Redman

> 6000.times do |i| > x = Hash.new > 1000.times do |j| > x[i]=j > puts x[i] # Just to actually do something. > end > end

But you would use this, of course:

puts (0..6000).map{(0..1000).to_a}

Docutils System Messages

System Message: ERROR/3 (<string>, line 1); backlink

Undefined substitution referenced: "i".

System Message: ERROR/3 (<string>, line 1); backlink

Undefined substitution referenced: "j".
# Jules

www.chwast.com www.jaram.pl www.kanaba.pl www.ganja-land.pl http://www.chwast.com http://www.jaram.pl http://www.kanaba.pl http://www.ganja-land.pl

# chwascior

From the Cherry Flow wiki page referenced: " The only catch is the back and refresh buttons won't work unless you run Stackless or Statesaver. " So, how does Cherry Flow work without Stackless? It doesn't really.

# Jeremy Dunck

Please forgive my uninformedness: Is it possible to NOT distribute source of a web application in either python/pythonpaste/django or ruby/rails (sort of like Java's byte-code-only WARs)? I'm thinking of prototyping a webapp in one of these languages but don't want to deliver my newbie code.

Thanks in advance for any reply.

# Michael

It is possible to distribute the PYC files (bytecode) or PYO (bytecode with docstrings stripped), but just as Java bytecode is hella easy to "decompile" pyc/pyo is trivial to get back into readable code blocks.

# Masklinn

At the the beginning of this year it seemed as if everyone was complaining about how many frameworks are available for Python, and now as Python junkies are evaluating Ruby they have been touting the large number of libraries as one of Python strengths.

I understand the frustration with multiple frameworks, but the available options are also a big reason I'm still using Python. In some ways I like Ruby as a language more, but the range of libraries give me a more control.

Who knows...as far as mass adoption is concerned, the framework or the available libraries may have more impact that the specific virtues of languages with as much synergy as Python and Ruby.

# Eric Radman

About OO: Ruby has the public, protected and private restrictions, while Python hasn't (even if private members can somewhat be __faked).

# Chris

I'm fairly new to Python (9 months or so), but there are two things I have found particularly frustrating. I'm curious to hear if Ruby has done better.

# Alec Wysoker

Thanks for the great article!

Some ideas:

I think Python's property() syntax is unwieldy compared with Ruby's for the same functionality, which may be the reason there are so many getters and setters in Python code that could have been properties.

Concerning Ruby code blocks: I have some ideas where requiring named functions can be quite tedious in addition to asynchronous code.

# Ori Peleg

AFAIK, Python does not have lexical closures/scoping which function in the "usual" (e.g. lisp, javascript) or intuitive manner. Lexically closed variables are read-only. See http://groups.google.com/group/comp.lang.python/browse_frm/thread/cf66057c1f9a9141/ for examples and details. I can not speak about Ruby on this point, though I have been lead to believe that its closures are the "usual" kind.

Cheers!

# Todd DeLuca

Lexically closed variables are read-only.

Wrong. Lexically closed names are read-only. That's because Python doesn't distinguish between assignment and binding.

Ruby seems to do, though. I actually find this counter-intuitive, as both assignment and binding use the same syntax.

# Matthias Benkard

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I hit a Python error. I'd post the traceback, but that seems to exacerbate the errors.

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I hit a Python error. I'd post the traceback, but that seems to exacerbate the errors.

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I got a Python error.

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I got a Python error:

/home/blog/src/Wiki/Context/Main.py
Traceback (most recent call last):
File "/home/sodafired/Webware/WebKit/Application.py", line 436, in dispatchRawRequest [edit]
self.runTransaction(trans)
File "/home/sodafired/Webware/WebKit/Application.py", line 497, in runTransaction [edit]
self.runTransactionViaServlet(servlet, trans)
File "/home/sodafired/Webware/WebKit/Application.py", line 522, in runTransactionViaServlet [edit]
servlet.runTransaction(trans)
File "/home/blog/Plugins/Component/cpage.py", line 108, in runTransaction [edit]
self.respond(trans)

System Message: WARNING/2 (<string>, line 20)

Definition list ends without a blank line; unexpected unindent.

File "WebKit/HTTPServlet.py", line 51, in respond [edit] File "/home/sodafired/Webware/WebKit/HTTPContent.py", line 65, in respondToPost [edit]

System Message: ERROR/3 (<string>, line 22)

Unexpected indentation.
self._respond(transaction)

System Message: WARNING/2 (<string>, line 23)

Block quote ends without a blank line; unexpected unindent.
File "/home/blog/Plugins/Component/cpage.py", line 258, in _respond [edit]
self.handleAction(action)
File "/home/sodafired/Webware/WebKit/HTTPContent.py", line 199, in handleAction [edit]
getattr(self, action)()
File "/home/blog/src/Wiki/Context/Main.py", line 284, in save [edit]
self.page.save()
File "/home/blog/src/Wiki/lib/wikipage.py", line 590, in save [edit]
type=type)
File "/home/blog/src/Wiki/lib/wiki.py", line 301, in notifyChange [edit]
guid='http://%s%s?version=%s' % (

System Message: WARNING/2 (<string>, line 33)

Definition list ends without a blank line; unexpected unindent.

IndexError: list index out of range

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I got a Python error:

/home/blog/src/Wiki/Context/Main.py
Traceback (most recent call last):
File "/home/sodafired/Webware/WebKit/Application.py", line 436, in dispatchRawRequest [edit]
self.runTransaction(trans)
File "/home/sodafired/Webware/WebKit/Application.py", line 497, in runTransaction [edit]
self.runTransactionViaServlet(servlet, trans)
File "/home/sodafired/Webware/WebKit/Application.py", line 522, in runTransactionViaServlet [edit]
servlet.runTransaction(trans)
File "/home/blog/Plugins/Component/cpage.py", line 108, in runTransaction [edit]
self.respond(trans)

System Message: WARNING/2 (<string>, line 20)

Definition list ends without a blank line; unexpected unindent.

File "WebKit/HTTPServlet.py", line 51, in respond [edit] File "/home/sodafired/Webware/WebKit/HTTPContent.py", line 65, in respondToPost [edit]

System Message: ERROR/3 (<string>, line 22)

Unexpected indentation.
self._respond(transaction)

System Message: WARNING/2 (<string>, line 23)

Block quote ends without a blank line; unexpected unindent.
File "/home/blog/Plugins/Component/cpage.py", line 258, in _respond [edit]
self.handleAction(action)
File "/home/sodafired/Webware/WebKit/HTTPContent.py", line 199, in handleAction [edit]
getattr(self, action)()
File "/home/blog/src/Wiki/Context/Main.py", line 284, in save [edit]
self.page.save()
File "/home/blog/src/Wiki/lib/wikipage.py", line 590, in save [edit]
type=type)
File "/home/blog/src/Wiki/lib/wiki.py", line 301, in notifyChange [edit]
guid='http://%s%s?version=%s' % (

System Message: WARNING/2 (<string>, line 33)

Definition list ends without a blank line; unexpected unindent.

IndexError: list index out of range

# Marc

I'd like to thank you for this post.

I've been reading too many inane Python Vs. Ruby monologues lately from fan boys of both camps.

This was a well-written and interesting piece.

Hehe, kind of amusing that while posting this comment, I got a Python error.

# Marc

Fun, and good comparsion but OO is OO , u can't have 102% OO. like drawing is drawingu can'thave 102% drawing

# Mic

Nice article! One very important thing I miss in your article, however, is a comparison of documentation. Good language and library documentation is as much a part of a language as its most common interpreter or its standard library itself, which you do address. Finding your way in a language may actually depend a lot more on the actual docs available than on any "principle of least surprise" or whatever. Only after using both Python and Ruby for various projects, I realised how important this is - coming partly from a PHP background. No matter how ugly PHP as a language might be, its documentation, both in terms of quality of content as ease of use/accessibility, is way ahead of both Ruby's and Python's.

I personally find the python documentation extensive, but very very messy. A list of dict methods is here, things about how lists work is there, and please look underneath the table for string methods, thank you. Oh and if you look in a totally different place, you'll find that there are also global functions operating on strings, with the same names. Naturally, we did not make a link between these two places. To my experience, Ruby performs better here, having a very decent, but maybe a bit concise, reference for built-in classes and modules that is up to date. Its standard library is, i believe, documented even worse than Python's, though (but at least a bit more functionality is considered built-in).

# Egbert Teeselink

Nice article! One very important thing I miss in your article, however, is a comparison of documentation. Good language and library documentation is as much a part of a language as its most common interpreter or its standard library itself, which you do address. Finding your way in a language may actually depend a lot more on the actual docs available than on any "principle of least surprise" or whatever. Only after using both Python and Ruby for various projects, I realised how important this is - coming partly from a PHP background. No matter how ugly PHP as a language might be, its documentation, both in terms of quality of content as ease of use/accessibility, is way ahead of both Ruby's and Python's.

I personally find the python documentation extensive, but very very messy. A list of dict methods is here, things about how lists work is there, and please look underneath the table for string methods, thank you. Oh and if you look in a totally different place, you'll find that there are also global functions operating on strings, with the same names. Naturally, we did not make a link between these two places. To my experience, Ruby performs better here, having a very decent, but maybe a bit concise, reference for built-in classes and modules that is up to date. Its standard library is, i believe, documented even worse than Python's, though (but at least a bit more functionality is considered built-in).

# Egbert Teeselink

One big difference is overriding or extending built-in type objects. You mentioned the case of an operator, but like you said, that isn't a big deal. But how about overriding existing, or adding new, str methods? You can't tell me that isn't useful!

In Ruby:

class String
  def validate()
    if (self.include?(' '))
      return false
    return true
    end
  end
end

puts('This should have no spaces'.validate())
>> false

In Python (just a PoC):

def validate():
  if (' ' in self):
    return False
  return True
str.validate = validate

print('This should have no spaces'.validate())
>> TypeError: can't set attributes of built-in/extension type 'str'

Don't get me wrong - I like Python. I use it alot (in fact, these days, more often than Ruby). I just wish it let me setattr on built-in objects.

# MonkeeSage

Well. Writing documentation for PHP is simpler that for Python or Ruby as PHP is only a collection of functions in a single namespace. Not talking down to PHP in any way with that. But it's limited structure is quite simple to document.

# Jon Gretar

One big difference is overriding or extending built-in type objects. You mentioned the case of an operator, but like you said, that isn't a big deal. But how about overriding existing, or adding new, str methods? You can't tell me that isn't useful!

In Ruby:

class String
  def validate()
    if (self.include?(' '))
      return false
    return true
    end
  end
end

puts('This should have no spaces'.validate())
>> false

In Python (just a PoC):

def validate():
  if (' ' in self):
    return False
  return True
str.validate = validate

print('This should have no spaces'.validate())
>> TypeError: can't set attributes of built-in/extension type 'str'

Don't get me wrong - I like Python. I use it alot (in fact, these days, more often than Ruby). I just wish it let me setattr on built-in objects.

# MonkeeSage

I think you guys are all wrong, and don't know what the hell you are talking about.

# Runt