Hacker News new | ask | show | jobs
by lobster_johnson 4945 days ago
> the idiom of using hashes as named arguments working well enough that the core team didn't feel the need to address it earlier

Hashes are hideously expensive, though: For every method call, an entire object has to be populated and hashed. The hashing is fast enough for symbol keys, sure, but it's still a whole data structure that must be allocated and later garbage collected.

Since Ruby hashes are mutable and there is no way to track the mutation across methods, the compiler cannot optimize single-use hash literals into a constant. (When all keys and literals are values it could pre-allocate a structure that is copy-on-write internally, but to my knowledge it doesn't do this.) For example, this is a typical pattern:

    def generate_useless_stuff(options = {})
      path = options[:path] || @default_path
      value = options[:value]
      File.open(path, "w") { |f| f << ("*" * value) }
    end

    generate_useless_stuff(value: 42)
In a statically-typed language, the compiler would know that {value: 42} was created once and never reused, and since the value is a literal, the :value key could simply have been plugged directly into the value variable. Also, the lookup of :path is completely unnecessary in this case.

Often all the options are optional, and even then a call to generate_useless_stuff() will generate an empty hash. This is why I tend to write methods, when performance-sensitive, as:

    def generate_useless_stuff(options = nil)
      path = options[:path] || @default_path if options
      value = options[:value] if options
      File.open(path, "w") { |f| f << ("*" * value) }
    end
Of course, this decreases allocation while adding complexity.

So yes, I absolutely agree that it's amazing. :-) I think the core team should have considered it earlier.

1 comments

Some might argue that if you're using Ruby and are worried about the cost of hashes, you might want to consider switching to another language. There are other concerns about "expensiveness" in Ruby that far outweigh usage of hashes.
That seems like a false dichotomy to me. Clearly I can worry about the cost of hashes and be using Ruby productively and performantly. (Unless I were writing programs whose performance was really dependent on hash performance; I don't use Ruby in those cases.)

Anyway, everything adds up. Even for webapps in Rails or Sinatra, the sheer number of method calls in a single template may contribute significant overhead to the rendering of a page. Which means that shaving a few microseconds off a method call may in fact boost performance measurably. I am hoping this will be the case with named arguments.