Never been to DZone Snippets before?

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

High-performance Ruby: faster Symbol.to_s (See related posts)

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 on this post

NoKarma posts on Aug 15, 2006 at 19:41
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
ciconia posts on Aug 15, 2006 at 20:06
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
rtomayko posts on Aug 16, 2006 at 00:05
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.
trans posts on Aug 16, 2006 at 00:23
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.
ciconia posts on Aug 16, 2006 at 06:46
Thanks trans. I updated the snippet.
jney posts on Jan 06, 2008 at 20:07
don't use this trick because it makes a conflict with ruby/date. you would go a frozen string error.

You need to create an account or log in to post comments to this site.


Click here to browse all 5141 code snippets

Related Posts