snax

ruby performance

tap sux

Hey, so Ruby trunk has a tap method. It takes a block but always returns self, so that you can chain ! methods. You save memory by modifying yourself in-place:

("BIG" * 10000000).tap(&:reverse!).split("G")

But a whole closure for that tiny bit of work? If you're chaining multiple calls on anything other than String you better watch out for Demeter. And there are already these crazy things called "locals" :

>> RUBY_VERSION 
=> "1.9.0"
>> benchmark { 100000.times { "string".tap{|s| s.downcase!} } }
0.107108 seconds
=> 100000
>> benchmark { 100000.times { s = "string"; s.downcase!; s } }
0.07488 seconds (-30% change)

This is an improvement over 1.8.6, but still. Take a cue from Rail's returning, which should never be used. Be like Python. Skip tap.

returning('') do |z| 
  raise FAIL 
end

There's also been some discussion of adding Array#crack. So many jokes...

November 15, 2007

10 comments

Jared says (November 17, 2007):

I’m actually a big fan of Rails’ returning, especially in building things like dynamic navigation structures. The following seems much more concise to me than instantiating an empty array, populating it, then returning it explicitly.

    returning Array.new do |topics|
      topics << [events_path, “View All”]
      topics << [event_path(event), "Details"]
      topics << [edit_event_path(event), "Edit"]
    end

Robin says (November 17, 2007):

I don’t like tap either. The same thing with that strange “fluent programming style”.

Jared, what’s wrong with:

  topics = []
  topics << [events_path, “View All”]
  topics << [event_path(event), "Details"]
  topics << [edit_event_path(event), "Edit"]
  topics

trans says (November 17, 2007):

Returning reads well enough but is it really better than:


topics = []
topics << [events_path, “View All” ]
topics << [event_path(event), "Details"]
topics << [edit_event_path(event), "Edit"]
topics

And actually you don’t even need the last line in this case.

evan says (November 16, 2007):

You don’t even need the first line, if you change the << to =.

Robin says (November 17, 2007):

Or just directly do:

  [[events_path, “View All”],
   [event_path(event), "Details"],
   [edit_event_path(event), "Edit"]]

evan says (November 17, 2007):

Quite so. Not the best example because it can be written purely functionally.

I think some of the appeal of returning comes from the desire to have a temporary named variable without leaking into the main namespace. But that's a syntactic problem, not a semantic problem, and it doesn't make sense to reduce readability and execution speed for it.

Jared says (November 17, 2007):

OK, point taken. It wasn't the best example, but Evan offers the explanation I would have given, it gives me access to a named variable without having to release it into the wild.

Someone ought to let Dave Thomas know about this, though, because he's strongly pitching the above technique at Pragmatic Studio events...

manveru says (November 20, 2007):

tap is not thought for modification but for inspection; bang-methods still shouldn't be chained.

See discussion at: http://tinyurl.com/2tyyjh

Gregory Brown says (November 21, 2007):

I agree with manveru that tap is useful for inspection; it's nasty for modification.

Also, I think you missed the chance for a funnier title: "tap is crap"

evan says (November 20, 2007):

manveru: That's a good point, and it explains the naming. So we should say, "no tapping in production", rather than "no tapping".

Add a comment

Various HTML tags allowed. Use <pre> for code blocks and <code> for inline references.