Ian Bicking: the old part of his blog

Re: Ruby, Python, "Power"

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!

Comment on Ruby, Python, "Power"
by Florian Gross

Comments:

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