Live data from Hacker News

Some Smalltalk about Ruby Loops

tech.stonecharioteer.com

11–20 of 59 posts

Re: Some Smalltalk about Ruby Loops

#11
post #5

> But Python also looks up methods at runtime. Does that mean Python also does message passing? Not quite. I don't think Ruby's "message passing" is fundamentally different from Python's "method calls". Ultimately, both languages implementations are very similar: both look up methods by name in a hash table and then call them. IMO "message passing" is just an alternative metaphor for what Ruby does when you type `obj…

> both look up methods by name in a hash table and then call them.

Except Ruby doesn't? cue `method_missing`. If you take only trivial examples you're not going to see much difference, this starts to show when you involve more advanced situations e.g with inheritance, and then you're drilling into singleton classes.

> Ruby immediately calls the method once it's found, whereas Python (generally) doesn't - instead it returns a binding to be called later

Again incorrect, `foo.bar` in Ruby and Python are two very fundamentally different things.

Python returns a binding to a method because it's an attribute accessor; when you throw inheritance into the mix it ends up that that attribute is inherited from the parent class, bound to the instance (which really in python means pass `self` as first argument), and - schematically - adding `()` after that ends up calling that bound method. If there's no attribute that's a no method error. It's all very C-ish and make believe, barely a notch above Go structs and their functions. The closest parallel in Ruby would be `foo.method(:bar).call()`

By contrast Ruby is going to send the :bar message along the inheritance chain, and if someone can respond it's going to invoke the responder's code, and surprise surprise method_missing happens only if it has exhausted inheritance but it's itself a method-slash-message; Oh and by the way the message passing is naturally so lazy that you can actually modify the inheritance chain -in flight- and inject a parent responder right before calling `super`. The whole notion of `binding` is a very concrete construct, way more rich that simply "hey I'm passing self as first argument". It becomes even more strange to "C&al. folks" when you start to involve singleton classes and start to realise weird things like Ruby classes are merely instances of the class Class and it's all instance turtles all the way down and all stupidly simple but you gotta have to wrap your head around it.

I surmise that so many differences and surprises have with Ruby are because most languages have some ALGOL legacy and Ruby is a conceptual heir to Smalltalk (and LISP†); the whole concept of open classes being another one: nothing is ever "finished" in Ruby!

Most of the time you don't have to care about these differences, until you do.

† While code isn't quite S-expr data in Ruby, there are more than enough first-class facilities that you can create and inject code entirely dynamically without resorting to `eval`ing strings.

Re: Some Smalltalk about Ruby Loops

#12
Even something as basic as "if" is done with message passing and blocks in Smalltalk.

There's a method named "ifTrue:ifFalse:" in Smalltalk (with each ":" expecting an argument, in this case, a block).

You can also chain messages and make phrases: `anObject aMethod; anotherMethod; yourself.`

The Ruby equivalent has repetition: `an_object.a_method; an_object.another_method; an_object`

or requires a block: `an_object.tap { _1.a_method; _1.another_method}` (and we usually use newlines instead of ";")

Re: Some Smalltalk about Ruby Loops

#13

I loved Smalltalk when I had to learn it for my first job out of college. Clean and clear OO with a flexible, play-inside-of-your-code runtime. Unfortunately the Smalltalk community is pretty small. So imagine my delight when I found Ruby in 2005. It took the best of Perl and the best of Smalltalk and gave it a much better syntax than either, plus it had a massively growing community. Ruby breaks a lot of the rules f…

Not all the best parts of Smalltalk, otherwise a IDE based experience with a JIT compiler would be there from the early days, that is an integral part of Smalltalk experience as developer.

Re: Some Smalltalk about Ruby Loops

#14

Even something as basic as "if" is done with message passing and blocks in Smalltalk. There's a method named "ifTrue:ifFalse:" in Smalltalk (with each ":" expecting an argument, in this case, a block). You can also chain messages and make phrases: `anObject aMethod; anotherMethod; yourself.` The Ruby equivalent has repetition: `an_object.a_method; an_object.another_method; an_object` or requires a block: `an_object.t…

I have found that chaining things in Smalltalk get immensely painful after just a couple elements. Unlike most other languages, I find myself reaching for silly little var names for lots of different things I would normally just let flow.

Re: Some Smalltalk about Ruby Loops

#15
post #3

Author here, I'd already shared it here. https://news.ycombinator.com/item?id=45644349

Thank you for this article. It makes it easier to explain to newcomers to Ruby why not to use the `for` keyword.

Thanks for reading. I didn't expect to hit HN Front page a second time this month!!

Re: Some Smalltalk about Ruby Loops

#17
post #3

Author here, I'd already shared it here. https://news.ycombinator.com/item?id=45644349

Thank you for this article. It makes it easier to explain to newcomers to Ruby why not to use the `for` keyword.

You might like my other post too

https://tech.stonecharioteer.com/posts/2025/ruby-blocks/

Re: Some Smalltalk about Ruby Loops

#18

Like Alan Kay himself said, it wasn't about objects, but about messaging. [0] [0] https://lists.squeakfoundation.org/pipermail/squeak-dev/1998...

Agreed. While I think matz is a great language designer, I loved Alan Kay's philosophy. I'd like some language that is OOP centric in nature, fast, has an elegant syntax and learns from erlang's model (elixir isn't it unfortunately, but some ideas it got right).

If you want OOP than, yes, Elixir isn't it... maybe Pony? Curious what else you don't like about Elixir though besides not being OOP... it's definitely got messaging!

Re: Some Smalltalk about Ruby Loops

#20
A while back I tried out SuperCollider for programmatic music generation... I distinctly remember thinking, "this language feels like some weird awkward blend of Smalltalk and Ruby".

Somehow I hadn't thought of the two as similar or related to each other.

Anyway, certainly you can write in this style in Python, since functions are first-class objects. It just has limits on its anonymous functions, and doesn't happen to provide a `times` method on integers (at least partly because the old parser would have struggled with seeing `10.times` and thinking "this should be a floating-point number, but `t` isn't a decimal digit").

  >>> class rint(int): # r for Ruby, of course
  ...     def times(self, func):
  ...         for i in range(self):
  ...             func(i)
  ... 
  >>> rint(3).times(print)
  0
  1
  2
> In Python, Java or C++, calling object.method() asks the compiler to find the method in the class and call it.

This is incorrect, as noted later. In Python, the lookup occurs at runtime. It also checks the object first, in most cases.

... The writing keeps anticipating my objections and then sort of correcting them and leaving something else not quite right. So trying to edit as I read has been frustrating. The point being, I just don't buy the philosophical difference that the author is trying to draw.

In Python the reason you're dealing with "attributes" rather than "messages" is because functions are first-class objects, which entails that they'll be treated the same way as ordinary data. A method call is two separate steps — the method-lookup and the actual attempt to "call" the result — which also has the implication that you can cache a "bound method" for later use. (By comparison, Ruby lets you "cache" the symbol, which in Python-think looks like some kind of magic string that tries to look itself up as an attribute name on other objects.)

But, I contend, this doesn't meaningfully change how the language is used overall.

> By including Enumerable and by implementing each, we get access to so many methods that we didn’t need to manually implement.

Okay, but in Python `map` and `filter` are just builtin functions, and you can use list comprehensions and `functools.reduce`. It's just a difference between external and internal iteration.

Post reply on HN