solnic/coercible — pull request #15 by jstepien (2014-04-02 15:08:19+00:00)
Title: Raise less exceptions in Coercer::String

This patch reduces the number of exceptions raised internally in
Coercer::String when dealing with incoercible values. The motivation
for this change is the cost of raising an exception.

Instead of raising an exception in the private #to_numeric method the
COERCION_FAILURE object is returned. This reduces the number of exceptions
from 2 to 1 in case of #to_float and from 3 to 2 in case of #to_integer.

Consider a following benchmark evaluating the influence of this patch.

```ruby
require 'benchmark'
require 'coercible'

def test_case(coercer)
100_000.times do
begin
coercer[String].to_integer "asdf"
rescue
end
end
end

coercer = Coercible::Coercer.new
raise unless 0.5 == coercer[String].to_float("0.5")

# warm up before measurements
test_case(coercer)
bm = Benchmark.measure { test_case(coercer) }
p bm
```

On JRuby 1.7.10 running on OpenJDK 64-Bit Server VM 1.7.0-u60-b01-20131204
this patch improves the benchmark result by 33%. It's exactly one third
because we got rid of 1 out of 3 exceptions; that's how expensive they are!

If you replace #to_integer with #to_float the improvement is even more
apparent; it's nearly 50%. The reason is removal of 50% of exceptions.

Notice that if we would take further steps in this direction and reduce the
number of exceptions raised in #to_integer to 1 we could bring the total
improvement to 66%.

Interestingly enough, on MRI 2.1.1 this patch brings 10% improvement in
case of #to_integer and nearly 30% in case of #to_float. Raising
exceptions isn't that expensive there as on JVM but it still comes with a
noticeable cost.

I did my best to maintain full compatibility of the public API.