2007/11/27, MonkeeSage <MonkeeSage / gmail.com>:
> On Nov 26, 11:46 pm, Mr Magpie <gazmcghees... / yahoo.com.au> wrote:
> > The benefits my suggestion provides are :
> > 1) allows an application specific default (of any type) to be supplied,
> > reducing code required.
> > 2) allows bad input to be unambigously detected, which (can distinguish
> > "fds".to_i from "0".to_i)
> > 3) because the result of to_i always evaluates to true, you can't do
> >      num.to_i ? 'valid int' : 'invalid int'
> > but with my sugestion you could do
> >      num.to_i(false) ? 'valid int' : 'invalid int'
> > 4) would be a miniscule change to the existing optimised C unlike some
> > monkey patch I could do
> > 5) would avoid performance-sapping exceptions
> > 6) would avoid expensive regular expressions
> > 7) as a default parameter, wouldn't affect existing code.
>
> I could be dense; well, I probably am. No, I'm sure about it. ;) But
> let me give it a go anyhow...
>
> All of the functionality you mention can be had now, it's just that it
> wouldn't be as fast. So most of the points are moot. Only 5 & 6
> remain. Also, 7 isn't exactly true, since it would require a extra
> compare operation in the back-end to see if a default was given and
> return that, or else return 0. But that is probably negligible.
>
> Regarding 5 & 6. I benchmarked some code against the default to_i/_f.
> Here are the code and the results:
>
> $ cat test.rb && ./test.rb
> #!/usr/bin/env ruby
>
> class String
>   def to_i2(default=0)
>     Integer(self) rescue default
>   end
>   def to_f2(default=0)
>     Float(self) rescue default
>   end
>   def num?
>     self =~ /^[-+.0-9]+$/
>   end
>   def to_i3(default=0)
>     self.num? ? self.to_i : default
>   end
>   def to_f3(default=0)
>     self.num? ? self.to_f : default
>   end
> end
>
> require 'benchmark'
>
> s1 = "10"
> s2 = "10a"
> s3 = "1.0"
> s4 = "1.0a"
>
> n = 1000000
> Benchmark.bm { |x|
>   x.report("to_i valid   ") { n.times { s1.to_i  } }
>   x.report("to_i invalid ") { n.times { s2.to_i  } }
>   x.report("to_f valid   ") { n.times { s3.to_f  } }
>   x.report("to_f invalid ") { n.times { s4.to_f  } }
>   x.report("to_i2 valid  ") { n.times { s1.to_i2 } }
>   x.report("to_i2 invalid") { n.times { s2.to_i2 } }
>   x.report("to_f2 valid  ") { n.times { s3.to_f2 } }
>   x.report("to_f2 invalid") { n.times { s4.to_f2 } }
>   x.report("to_i3 valid  ") { n.times { s1.to_i3 } }
>   x.report("to_i3 invalid") { n.times { s2.to_i3 } }
>   x.report("to_f3 valid  ") { n.times { s3.to_f3 } }
>   x.report("to_f3 invalid") { n.times { s4.to_f3 } }
> }
>
>
>       user     system      total        real
> to_i valid     1.160000   0.110000   1.270000 (  1.307932)
> to_i invalid   1.180000   0.100000   1.280000 (  1.318455)
> to_f valid     1.570000   0.190000   1.760000 (  1.788322)
> to_f invalid   1.980000   0.090000   2.070000 (  2.105102)
> to_i2 valid    2.310000   0.350000   2.660000 (  2.703812)
> to_i2 invalid 39.640000   1.240000  40.880000 ( 42.264511)
> to_f2 valid    2.880000   0.310000   3.190000 (  3.377140)
> to_f2 invalid 40.680000   1.100000  41.780000 ( 43.211592)
> to_i3 valid    6.470000   0.390000   6.860000 (  6.975072)
> to_i3 invalid  3.400000   0.350000   3.750000 (  3.959219)
> to_f3 valid    7.250000   0.320000   7.570000 (  7.605764)
> to_f3 invalid  3.600000   0.380000   3.980000 (  4.005525)
>
>
> As you can see, you were correct about point 5 when it is the
> exceptional case; however, regarding point 6, performance is close to
> within an order of magnitude of the built-in versions of to_i/_f.
> That's not too awful.
>
> If I may make three counter-points against your suggestion:
>
> 1.) It is wierd and completely unintuitive for to_i to return anything
> *other than integer*! Maybe it's just me, but that would be like
> calling to_a and getting back a String. Holy return types Batman, what
> gives?
>
> 2.) Would a non-zero default really be used enough (or in cases where
> the speed of using something like the code I listed above with regexps
> is not fast enougg) to warrant inclusion? Do you have any real world
> examples that are not just corner-cases?
>
> 3.) (Like Ara said...) If you're worried about the performance of
> exceptions, how helpful is it to do something like: "10a".to_i(nil) %
> 2? That's either going to terminate with a NoMethodError, or you'll
> have to rescue it (eating just as much cycles).

Another point you did not mention (as far as I can see): optimizing
the performance of the /exceptional/ case is likely to yield only
minor benefits if at all.

Kind regards

robert

-- 
use.inject do |as, often| as.you_can - without end