Performance Zone is brought to you in partnership with:
DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

High-performance Ruby: Faster Symbol.to_s

08.15.2006
| 9192 views |
  • submit to reddit
        Here's something that I found useful for shaving a few microseconds off. The performance gain ranges between 10% and 35%! YMMV.

Note: updated with suggestion by trans.

class Symbol
  def to_s
    @str_rep || (@str_rep = id2name.freeze)
  end
end
    

Comments

jean-sébastien ney replied on Fri, 2007/03/30 - 6:30pm

don't use this trick because it makes a conflict with ruby/date. you would go a frozen string error.

Snippets Manager replied on Mon, 2012/05/07 - 2:26pm

Thanks trans. I updated the snippet.

Thomas Sawyer replied on Wed, 2006/08/16 - 12:21am

You might try: class Symbol def to_s @to_s || (@to_s = id2name) end end That way you don't need to alias to_s first.

Snippets Manager replied on Mon, 2012/05/07 - 2:26pm

Reporting in with verification that the to_s_faster method is indeed the fastest on three different machines of varying architecture (PPC, x86, amd64). This kind of blew my mind because I had assumed that the to_s_fast and to_s_faster methods had the same semantics and were treated identically by the runtime. My current theory as to why the to_s_faster methods performs better is because the instance variable assignment is performed each time in the to_s_fast case (albeit to itself) but is not in the to_s_faster case. i.e. the following to_s_fast methods are all roughly equivalent (semantically): def to_s_fast @str_rep ||= to_s end def to_s_fast @str_rep = @str_rep || to_s end def to_s_fast instance_variable_set(:@str_rep, instance_variable_get(:@str_rep) || to_s) end def to_s_fast result = instance_variable_get(:str_rep) result = to_s if result.nil? instance_variable_set(:@str_rep) end What I'm trying to call out is that the instance_variable_set method may be invoked each time. Compare to these (again, roughly equivalent versions of the to_s_faster) method: def to_s_faster @str_rep || (@str_rep = to_s) end def to_s_faster return @str_rep unless @str_rep.nil? @str_rep = to_s end def to_s_faster instance_variable_get(:@str_rep) || instance_variable_set(:@str_rep, to_s) end Can anyone confirm or deny this? I use "@x ||= y" quite frequently and had assumed the variable assignment didn't take place if the LHS of the || was truthful.

Snippets Manager replied on Mon, 2012/05/07 - 2:26pm

Hi NoKarma. Tried it. My way is faster, but you can try it yourself: require 'benchmark' class Symbol def to_s_fast @str_rep ||= to_s end def to_s_faster @str_rep || (@str_rep = to_s) end end n = 1000000 Benchmark.bm do |x| x.report {n.times {:hello.to_s}} x.report {n.times {:hello.to_s_fast}} x.report {n.times {:hello.to_s_faster}} end

Snippets Manager replied on Tue, 2006/08/15 - 7:37pm

hmm, nice Idea. but to make this code a little bit more beatiful, you can do this: class Symbol alias_method :__orig_to_s, :to_s def to_s @str_rep ||= __orig_to_s.freeze end end