tags:

views:

571

answers:

8

Do you know if using double quotes instead of single quotes in ruby decreases performance in any meaningful way in ruby 1.8 and 1.9.

so if I type

question = 'my question'

is it faster than

question = "my question"

I imagine that ruby tries to figure out if something needs to be evaluated when it encounters double quotes and probably spends some cycles doing just that.

+1  A: 

It will only make a (minute) difference when your code is parsed. When is gets executed it will be exactly the same.

I suggest you use double quotes everywhere. This makes it easier to actually add that #{some_var} later on.

Marc-André Lafortune
I'm more concerned about
Andy Lester
A: 

It's certainly possible depending on the implementation, but the scanning portion of the interpreter should only look at each character once. It will need just an additional state (or possible set of states) and transitions to handle #{} blocks.

In a table based scanner thats going to be a single lookup to determine transition, and will be happening for each character anyways.

When the parser gets the scanner output, it's already known that it will have to eval code in the block. So the overhead is only really the memory overhead in the scanner/parser to handle the #{} block, which you pay for either way.

Unless I'm missing something (or misremembering compiler construction details), which is also certainly possible :)

BioBuckyBall
+13  A: 
$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]

$ cat benchmark_quotes.rb
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
end

$ ruby -w benchmark_quotes.rb 
      user     system      total        real
assign single  0.670000   0.250000   0.920000 (  0.967755)
assign double  0.620000   0.290000   0.910000 (  0.953019)
concat single  1.600000   0.370000   1.970000 (  1.988251)
concat double  1.610000   0.360000   1.970000 (  2.090870)
zetetic
No interpolation?
Erik Escobedo
see madlep's answer below
zetetic
Am I interpreting the results correctly? Assignment using double quotes is actually faster than single? How can this be?
randomguy
Apparently yes, though the difference is minor. As to why -- beats me.
zetetic
+8  A: 

No difference - unless you're using #{some_var} style string interpolation. But you only get the performance hit if you actually do that.

Modified from Zetetic's example:

require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assign interp") { n.times do; c = "a #{n} string"; end}  
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
  x.report("concat interp") { n.times do; "a #{n} string " + "b #{n} string"; end}
end

output

               user       system     total    real
assign single  0.370000   0.000000   0.370000 (  0.374599)
assign double  0.360000   0.000000   0.360000 (  0.366636)
assign interp  1.540000   0.010000   1.550000 (  1.577638)
concat single  1.100000   0.010000   1.110000 (  1.119720)
concat double  1.090000   0.000000   1.090000 (  1.116240)
concat interp  3.460000   0.020000   3.480000 (  3.535724)
madlep
Interesting. Interpolation looks a bit more expensive. Was this 1.8? It would be nice to see if 1.9 changes anything.
zetetic
zetetic - yup. This was against Ruby 1.8.7
madlep
+4  A: 

No one happened to measure concatenation vs interpolation though:

$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.6.2]
$ cat benchmark_quotes.rb
require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assing interp") { n.times do; c = "a string #{'b string'}"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
end

$ ruby -w benchmark_quotes.rb 
      user     system      total        real
assign single  2.600000   1.060000   3.660000 (  3.720909)
assign double  2.590000   1.050000   3.640000 (  3.675082)
assing interp  2.620000   1.050000   3.670000 (  3.704218)
concat single  3.760000   1.080000   4.840000 (  4.888394)
concat double  3.700000   1.070000   4.770000 (  4.818794)

Specifically, note assign interp = 2.62 vs concat single = 3.76. As icing on the cake, I also find interpolation to be more readable than 'a' + var + 'b' especially with regard to spaces.

Tim Snowhite
A: 

Single quotes can be very slightly faster than double quotes because the lexer doesn't have to check for #{} interpolation markers. Depending on implementation, etc. Note that this is a parse-time cost, not a run-time cost.

That said, the actual question was whether using double quoted strings "decreases performance in any meaningful way", to which the answer is a decisive "no". The difference in performance is so incredibly small that it is completely insignificant compared to any real performance concerns. Don't waste your time.

Actual interpolation is a different story, of course. 'foo' will be almost exactly 1 second faster than "#{sleep 1; nil}foo".

ReinH
+2  A: 

Thought I'd add a comparison of 1.8.7 and 1.9.2. I ran them a few times. Variance was about +-0.01.

require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assign interp") { n.times do; c = "a #{n} string"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
  x.report("concat interp") { n.times do; "a #{n} string " + "b #{n} string"; end}
end

ruby 1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux]

assign single  0.180000   0.000000   0.180000 (  0.187233)
assign double  0.180000   0.000000   0.180000 (  0.187566)
assign interp  0.880000   0.000000   0.880000 (  0.877584)
concat single  0.550000   0.020000   0.570000 (  0.567285)
concat double  0.570000   0.000000   0.570000 (  0.570644)
concat interp  1.800000   0.010000   1.810000 (  1.816955)

ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]

  user          system      total      real
assign single  0.140000   0.000000   0.140000 (  0.144076)
assign double  0.130000   0.000000   0.130000 (  0.142316)
assign interp  0.650000   0.000000   0.650000 (  0.656088)
concat single  0.370000   0.000000   0.370000 (  0.370663)
concat double  0.370000   0.000000   0.370000 (  0.370076)
concat interp  1.420000   0.000000   1.420000 (  1.412210)
PhilT
+1 for looking at variance.
Andrew Grimm
A: 

There is no significant difference in either direction. It would have to be huge for it to matter.

Except for times when you are sure that there is an actual problem with timing, optimize for programmer maintainability.

The costs of machine time are very very small. The costs of programmer time to write code and maintain it is huge.

What good is an optimization to save seconds, even minutes of runtime over thousands of runs if it means that the code is harder to maintain?

Pick with a style and stick with it but do not pick that style based on statistically insignificant milliseconds of runtime.

Andy Lester