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