00:00
1648
This talk was given at Northwest Python Day 2010. The companion blog post is at blog.extracheese.org/2010/02/python-vs-ruby-a-battle-to-the-death.html

Credits

Likes

See all likes
  • banister fiend plus 1 year ago
    nice talk, but I think you got the slightly wrong end of the stick regarding Proc#call and friends.

    my_proc.call makes sense, because Proc is a class, and my_proc is an instance of Proc, not a function. Also you cannot overide () as an operator (probably because () are optional in Ruby), so they used the next best thing.

    Note that in Ruby 1.9 you can use the added sugar my_proc.() to invoke a Proc object
  •  
  • Georg Brandl 1 year ago
    About the assertRaises: I think that we'll have a very nice equivalent in unittest 2.7+:

    with self.assertRaises(TypeError):
    MyClass.add(2, "two")

    (and of course nose should add the same thing, with a nicer method name...)
  •  
  • banister fiend plus 1 year ago
    Also &:symbol is not 'core syntax', it's simply implementing the #to_proc method on the Symbol class. And if you understand that, it's easy to know when and where you can use it :)
  •  
  • Gary Bernhardt plus 1 year ago
    Banister, I know that Proc is a class. I know that &:symbol calls #to_proc. I know Ruby. :)

    I don't think either of these is relevant to my comments in the talk. The Proc issue *does* introduce inconsistency, and the &:symbol issue *does* introduce confusion.

    Proc#call makes sense for the compiler, but it does not, in my opinion, make sense for the programmer. It introduces two more syntaxes (#call and #[]) for a concept that already had two to begin with (calls with and without parens)!

    Yes, "core syntax" was the wrong term to use. It was late, I'd already given one talk five hours earlier on the same day, and I was tired. I apologize. Even with the poor choice of words, though, the point is the same – the history of &:symbol is confusing and user-hostile. I do not accept your argument that "it's easy to know", because my experience shows that Ruby programmers are widely confused by this issue.

    Despite my disagreements, thanks for the comment, and I'm glad that you liked the talk overall. :)
  • banister fiend plus 1 year ago
    I agree that it may be _annoying_ for a programmer to invoke a Proc object using #call but I cannot see how it is _inconsistent_. In fact it is Ruby's insistence _on_ consistency that results in the slightly inconvenient #call syntax in the first place.

    As you acknowledge yourself, a Proc is an object and so is 'invoked' by sending it a msg. In Ruby the `()` operator cannot be overloaded and so the #call message is used instead.

    What you are asking for, essentially, is that Ruby allow the '()' operator to be overloaded but _this_ would result in inconsistency as the '()' would then be mandatory when invoking Procs (and other user-defined functors) but not when invoking methods.

    It just doesn't make sense to allow overloading of the '()' operator in a language where parentheses are optional.

    Further, Common Lisp, a language you mention a few times in your talk, works in a similar way. Anonymous functions in Common Lisp cannot be invoked like 'normal' functions and must be invoked through a similar 'call' mechanism: (funcall my-lambda args ...).

    I'll grant you your point on &:symbol (I use it sometimes, but it does still feel like a clever hack)

    ;)
  •  
  • Gary Bernhardt plus 1 year ago
    Method is a class representing a callable object; methods are callable with parens. Proc is a class representing a callable object; procs are not callable with parens. This is inconsistent. The argument that "procs are objects" doesn't work, because methods are objects too.

    In Python, this distinction does not exist, even though it, too, has multiple callable types. Python has conceptual consistency here; Ruby does not. One nice benefit of this is that, in Python, you can pass any callable type to a function that expects a callable and it will just work – instancemethod, function, lambda, object with __call__ defined, it doesn't matter.

    This is not an absolute value judgement on Ruby. It's simply a *relative* value judgement – if we judge this syntax with respect to the pythonic standards in The Zen, it comes up deficient. That doesn't mean it's in a state of moral disarray, or that I think Ruby is fundamentally wrong in this way; it just means that Ruby doesn't live up to the set of standards the Python community happens to have settled on (not surprising!). That's all. :)
  • banister fiend plus 1 year ago
    No no no, you're confusing 'Method Objects' with 'methods'.

    A Method Object is a method wrapped up into an object so it can be passed around.

    Method Objects _cannot_ be invoked without using #call, they have an almost identical API to Procs, see:

    class HelloClass
    def hello; puts "hello"; end
    end

    m = HelloClass.new.method(:hello)
    m() #=> error, no method 'm'
    m.call #=> "hello", this actually invokes the Method Object

    A 'method' itself is not an object, rather it implements the behaviour OF an object.

    A 'method' _cannot_ be said to be an instance of the Method class. It is only when you call the #method(method_name) that the 'method' is wrapped up into a Method Object.

    Ruby is entirely consistent here - NO objects support the '()' operator, and methods are _not_ objects. The only way to invoke functors (Procs, Method Objects, and so on) in Ruby therefore is to explicitly send a message. In Ruby 1.8.6 the messages are #call and #[] and in Ruby 1.9 you can use #.().
  • banister fiend plus 1 year ago
    Also this duality of 'methods' and object-wrappers for methods (when the method needs to be passed around) is not at all unique to Ruby. Ruby inherited this from Smalltalk, and IIRC, Scala works in the same way.

    The only point of difference being that in some languages the '()' operator can be overloaded and so the distinction between 'method' and 'wrapped method object' is harder to perceive.
  •  
  • Gary Bernhardt plus 1 year ago
    It was a mistake to even bring code concepts into this. I accept that you are surely right about methods not being objects, but that's an implementation detail. None of this changes anything about what I said.

    From the start, I have not been talking about the implementation. I'm talking about my mental model of how software works. My brain contains the concept of "callable object". I want to treat this as a single, unified concept, interacting with all "callable object"s in the same way. Python lets me do this; Ruby does not. I don't care why this is the case – procs, methods, objects – who cares? The point I was trying to make in the talk is that the concept of "callable object" is not unified in Ruby; it's fractured. You're giving me the details of *why* it's fractured. That's fine, but it doesn't change my original statement.

    Once again, for good measure: it's not about the details of procs or methods. I'm talking about the concept of "callable object" that is present in the brains of some humans, including me, but is not present in a single canonical form in Ruby.

    I will reiterate that this is not an absolute value judgement – I'm not saying "my brain is Right; Ruby is Wrong." It's an almost entirely subjective issue.
  • banister fiend plus 1 year ago
    But the point is that 'methods', in Ruby, are _fundamentally_ different to Procs and so conflating them together as 'callable objects' is misgsuided (This is a result of the object oriented model Ruby uses, one shared with Smalltalk and Scala among others)

    This is different to the case in Python where AFAIK methods, functions, and lambdas really are just different kinds of 'functions' and so thinking of them together in this way as 'callable objects' makes more sense.

    In Ruby though, there is no unifying idea of a 'function' there are instead 'methods' and Procs (et al).

    The distinction between the two is that 'methods' are executable code bound to the state of an object but Procs are _objects_ that wrap 'free' code. These differences (esp. the fact that one is a full-blown Object and one is _not_) are so fundamental IMO that convolving the two ideas into a single notion of 'callable object' and then complaining about lack of 'consistency' is wrongheaded.

    Another issue altogether is whether, despite these fundamental differences, you can nonetheless provide them with the same interface. Scala (which also makes a similar distinction between methods and 'function objects') _does_ allow overloading of the '()' operator and so the interfaces are the same. Ruby, on the other hand, does not allow overloading of '()' and so the interfaces are different. This does _not_ mean that Scala is more 'consistent' than Ruby, it just means, on this particular point, that Scala is arguably more aesthetically pleasing.

    As I've stated before, it is because parentheses are optional in Ruby that the '()' operator cannot be overloaded. I agree that this results in slightly annoying #call syntax when invoking Procs but I think overall it is a win for Ruby's elegance. Personally I do not mind having to type #call to invoke a functor if what i'm gaining in return is an API with the beauty and elegance of Rake or Sinatra.

    Also, as I said before, having to use a call mechanism to invoke an anonymous function is not unique to Ruby, Common Lisp also works like this and I do not recall anyone calling CL 'inconsistent' on this point.
  •  
  • Gary Bernhardt plus 1 year ago
    The point I made requires three premises: (1) Ruby draws the distinction; (2) It's possible not to draw the distinction; (3) Forcing the programmer to draw a distinction where it can be avoided violates the literal word of The Zen of Python.

    That's my whole argument, man. We've wasted all of this time debating a point made in a few seconds of the most frivolous section of a silly talk filled to the brim with wild-ass statements. This is not worth the effort.

    It's OK for Ruby to be unpythonic. Everything is fine. The universe is at peace. Two languages have different design aesthetics; that's all. Nothing is wrong here. I do not want to continue discussing this! :)
  • banister fiend plus 1 year ago
    All I really took issue with was your use of the word 'inconsistent' in describing the Proc#call syntax. There is no inconsistency (as I've been at pains to demonstrate).

    However it seems you now hold the more innocuous view of "The two languages have different design aesthetics; that's all. Nothing is wrong here.".

    If this is the view you now hold, then we are in complete agreement. :)
  •  
  • Gary Bernhardt plus 1 year ago
    My view hasn't changed (although you have given me some learning about Ruby's guts). If you go back to the talk, you'll find that my complaint was about consistency with programmer expectations on syntax, not about internal consistency within the language.
  •  
  • Richard Feng 1 year ago
    To banister fiend:
    I found an old rant regarding closures(Proc, proc, etc)

    Please see
    innig.net/software/ruby/closures-in-ruby.rb

    After that, now you can tell me ruby is consistent...:-)
  • banister fiend plus 1 year ago
    @Richard, Gary and I were not arguing about the 'consistency' of Ruby in general but specifically about the Proc#call syntax.

    Nonetheless though that article makes some interesting points (esp. regarding the lack of multiple blocks) I really think the author is a bit hysterical. It is true there are some subtle differences between Procs, lambdas and blocks, but the situation is not nearly as byzantine as the author makes out. In my opinion most of the content in that article could be compressed to about 6 lines of code.
  •  
  • Martin Vilcans 1 year ago
    "Everything's awesome. We need blocks."

    Well put!
  •  
  • Anthony Green 1 year ago
    Yehuda Katz has posted a response '
    Ruby is NOT a Callable Oriented Language' on his blog yehudakatz.com/2010/02/21/ruby-is-not-a-callable-oriented-language/
  •  
  • Brahma 8 months ago
    which is the best program to learn Ruby or Python?
  •  
This conversation is missing your voice. Take five seconds to join Vimeo or log in.

Advertisement

About this video

MOV
00:27:28
  • 640x360, 56.17MB
  • Uploaded Mon February 15, 2010
  • Please join or log in to download

Statistics

Date Plays Comments
Totals 34.4K 86 18
Feb 14th 13 1 0
Feb 13th 28 0 0
Feb 12th 25 0 0
Feb 11th 31 0 0
Feb 10th 19 0 0
Feb 9th 36 0 0
Feb 8th 30 2 0