Archive for April, 2008

Will Rubinius have fewer dark corners?

Section 3.4.2 of The Ruby Programming Language talks about defining (or overriding) the hash and eql? methods of a class in order to control how objects are treated as keys in a hash… except for strings. Strings are handled specially because they’re “mutable but commonly used as hash keys.”

So when someone asked today on comp.lang.ruby about case-insensitive hash access, the answer, sadly, could not be as simple (and possibly dangerous) as “Just override hash and eql? in String.” Or could it?

Well, I whipped up something quickly:

class String
  alias old_hash hash
  def hash
    self.downcase.old_hash
  end

  def eql?(other)
    self.hash == other.hash
  end
end

require 'test/unit'

class TestCaseInsensitiveHashAccess < Test::Unit::TestCase
  def test_case_insensitivity
    h = {'a' => 1, 'B' => 'buzz'}
    assert_equal(1, h['A'])
    assert_equal('buzz', h['b'])
  end
end

I ran it a few times. Ruby failed. Ruby 1.9 failed. JRuby failed. But Rubinius passed.

And why shouldn’t it pass? For every other class, this sort of monkeying with hash and eql? will get you what you want: hash key access mayhem. Why not String?

Well, there might be something sinister hiding in the “mutable but commonly used as hash keys” description. Something subtle. Maybe it’s not subtle and I just haven’t been thinking very clearly. I don’t know.

It looks to me, in the short amount of time I’ve been thinking about this, that Rubinius is more consistently Ruby-ish than Ruby is (at least in this case). Are there more ways in which that’s true?

Comments

Evil: knowing when a method got passed the default value

Let’s say you’re crazy. Now, as a crazy person, you might have a method like this:

def greet_world(salutation="Hello")
  "#{salutation} World!"
end

You’re not so crazy that you can’t write working Ruby code. Anyway, it’s totally useful:

greet_world          # => "Hello World!"
greet_world('Hi')    # => "Hi World!"
greet_world('Yo')    # => "Yo World!"
greet_world('Hola')  # => "Hola World!"

But then you see someone do this:

greet_world('Hello')  # => "Hello World!"

And it drives you even crazier. Being totally crazy, you feel a compulsion to make fun of people who pass the default value for an argument of a method. But how in the world can you tell?

Well, it turns out (and you probably know this already) that the argument list of a method is a proper venue for executing code. You know this because you’ve seen this a thousand times: def something(time=Time.now). That Time.now happens when you call the method without that optional argument. It doesn’t happen when Ruby first parses the method and adds it to the method table for the class. That wouldn’t be too helpful.

So… you can execute arbitrary code in the method argument list. But what kind? What’s the scope? Well, anything you can do in a method body is fair game (and anything you can’t is not). You can’t define a class, for instance. And the scope? The method body itself.

You’re crazy, remember? But not so crazy that you don’t remember that every statement has a return value. Like assignment. Assignment returns a value. And you’ve got a place in the argument list that’s scoped with the method body. And you’ve got a deep desire to mock people who pass default values.

BOOM!

def greet_world(salutation=(salutation_not_given='Hello'))
  if salutation == 'Hello' and not salutation_not_given
    "YOU HAVE NO IMAGINATION!"
  else
    "#{salutation} World!"
  end
end

greet_world('Hello')  # => "YOU HAVE NO IMAGINATION!"
greet_world           # => "Hello World!"
greet_world('Hi')     # => "Hi World!"

salutation_not_given is nil if you’ve given a value. It’s one of those things.

ANYWAY. Use that at your own peril.

Comments (4)

MountainWest RubyConf videos (including my lightning talk on GuessMethod)

Confreaks have started putting up more video from MountainWest RubyConf, and today saw the addition of the lightning talks from day one. I’d like to draw particular attention to the second entry of this list of who talked when about what:

  1. Binary Lottery in Shoes - Mike Moore - 0:10
  2. GuessMethod - Chris Shea (me!) - 4:35
  3. ActiveScaffold - Ed Moss - 8:51
  4. Migration Concordance - Josh Susser - 12:39
  5. Framework Components - Jeremy McAnally - 18:05
  6. Systems Building Systems with Puppet - Andrew Schafer - 20:43
  7. Multi-image Uploading with SWFUpload and Rails - David South - 27:14
  8. RubyAmp: Ruby Dev in TextMate Amplified - Tim Harper - 31:55
  9. Build a GUI App in 5 Minutes - David Koontz - 37:46

Lots of interesting stuff in there. And I encourage everyone to look at other videos from the conference. It was great.

Comments