Ruby Is Not Ruby All the Way Down

ruby

This evening Gary Bernhardt posted a series of tweets pointing out that printing a stack trace (or backtrace, in ruby parlance) in order with the most recent method call at the top and oldest method call at the bottom, as most languages do, doesn’t make much sense. Application programmers are interested in the most recent method call much more often than they are interested in the deepest method call, so putting that information at the bottom, where their eyes will be on the terminal, would be better.

Apparently, Python is the only (common) language that gets this right. Being a Rubyist, I was immediately filled with hubris - well, Ruby isn’t anything without its fantastic metaprogramming capabilities.

If Exception were a normal class, we could just monkey-patch the exception class as follows:

1
2
3
4
5
6
7
8
class Exception
  alias :old_backtrace :backtrace

  def backtrace
    old_backtrace.reverse
  end

end

I threw that into a gem and defined a test file to make sure that my method would work appropriately. Certainly, I don’t know all the details of the ruby internals - I never had any delusion that this would be a good idea in a production environment, necessarily, but I certainly expected it to basically work.

Of course, it didn’t. Not only did it not work, but none of the regular debugging strategies that I tried to employ worked; alias the method worked so long as the new method directly called the old, but didn’t work otherwise. Putting a ‘puts’ statement would cause stack overflows; adding a .to_a on the old method (which shouldn’t do anything) caused no output to be sent at all, &c.

It turns out that Exception is defined directly in error.c in CRuby (also called MRI). It seems that overriding cRuby classes is not the same as overriding regular ruby classes.

Ruby isn’t rubies all the way down - eventually, you hit some C.

Happy Coding!