Why is == faster than eql?

benchmarking, equality, ruby, string

Solution

The reason you are seeing a difference is not related to the implementation of `==` vs `eql?` but is due to the fact that Ruby optimizes operators (like `==`) to avoid going through the normal method lookup when possible.

We can verify this in two ways:

Create an alias for `==` and call that instead. You'll get similar results to `eql?` and thus slower results than `==`.

Compare using `send :==` and `send :eql?` instead and you'll get similar timings; the speed difference disappears because Ruby will only use the optimization for direct calls to the operators, not with using `send` or `__send__`.

Here's code that shows both:

require 'fruity'
first = "Woooooha"
second = "Woooooha"
class String
  alias same_value? ==
end

compare do
  with_operator   { first == second }
  with_same_value { first.same_value? second }
  with_eql        { first.eql? second }
end

compare do
  with_send_op    { first.send :==, second }
  with_send_eql   { first.send :eql?, second }
end

Results:

with_operator is faster than with_same_value by 2x ± 0.1
with_same_value is similar to with_eql
with_send_eql is similar to with_send_op

If you're the curious, the optimizations for operators are in `insns.def`.

Note: this answer applies only to Ruby MRI, I would be surprised if there was a speed difference in JRuby / rubinius, for instance.

Problem

I read in the documentation for the String class that `eql?` is a strict equality operator, without type conversion, and `==` is a equality operator which tries to convert second its argument to a String, and, the C source code for this methods confirms that: The `eql?` source code: ``` static VALUE rb_str_eql(VALUE str1, VALUE str2) { if (str1 == str2) return Qtrue; if (TYPE(str2) != T_STRING) return Qfalse; return str_eql(str1, str2); } ``` The `==` source code: ``` VALUE rb_str_equal(VALUE str1, VALUE str2) { if (str1 == str2) return Qtrue; if (TYPE(str2) != T_STRING) { if (!rb_respond_to(str2, rb_intern("to_str"))) { return Qfalse; } return rb_equal(str2, str1); } return str_eql(str1, str2); } ``` But when I tried to benchmark these methods, I was suprised that `==` is faster than `eql?` by up to 20%! My benchmark code is: ``` require "benchmark" RUN_COUNT = 100000000 first_string = "Woooooha" second_string = "Woooooha" time = Benchmark.measure do RUN_COUNT.times do |i| first_string.eql?(second_string) end end puts time time = Benchmark.measure do RUN_COUNT.times do |i| first_string == second_string end end puts time ``` And results: Ruby 1.9.3-p125: ``` 26.420000 0.250000 26.670000 ( 26.820762) 21.520000 0.200000 21.720000 ( 21.843723) ``` Ruby 1.9.2-p290: ``` 25.930000 0.280000 26.210000 ( 26.318998) 19.800000 0.130000 19.930000 ( 19.991929) ``` So, can anyone explain why the more simple `eql?` method is slower than `==` method in the case when I run it for two similar strings?

Original source