Ian Bicking: the old part of his blog

Rubypythonpower comment 000

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.

Comment on Re: Ruby, Python, "Power"
by Ian Bicking

Comments:

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