On Feb 21, 2008, at 1:00 AM, Ryan Davis wrote:

> On Feb 20, 2008, at 15:12 , MenTaLguY wrote:
>
>> # of iterations = 1000000
>>                            user     system      total        real
>> null_time               0.218000   0.000000   0.218000 (  0.219000)
>> split/each/<<+         24.516000   0.140000  24.656000 ( 24.703000)
>> split/map/<<+          26.109000   0.172000  26.281000 ( 26.281000)
>> split/inject/<<+       30.797000   0.172000  30.969000 ( 31.000000)
>>
>> Being an FP nut used to using folds, I'm always a little annoyed that
>> inject fares so poorly in these things; mainly we're just lacking a
>> C implementation of Array#inject.
>
> coming back to this point... what do you mean by we're missing a C  
> impl of Array#inject? Granted, the impl is on Enumerable, but I  
> wouldn't think it would make THAT much of a difference... But I try  
> my best not to speculate (ever), so...
>
> (my C coding skills absolutely suck these days, please point out  
> improvements)
>
> #!/usr/bin/env ruby -w
>
> require 'benchmark'
> require 'ipaddr'
> $: << File.expand_path("~/Work/p4/zss/src/RubyInline/dev/lib")
> require 'inline'
>
> class Array
>  inline do |builder|
>    builder.c_raw <<-EOF
>      VALUE new_inject(int argc, VALUE *argv, VALUE self) {
>        long max = RARRAY(self)->len;
>        long i     = argc ? 0       : 1;
>        VALUE memo = argc ? argv[0] : RARRAY(self)->ptr[0];
>
>        for (i; i < max; i++) {
>          memo = rb_yield_values(2, memo, RARRAY(self)->ptr[i]);
>        }
>
>        return memo;
>      }
>    EOF
>  end
> end
>
> p "127.0.0.1".split('.').inject(0) { |s,n| (s << 8) + n.to_i }
> p "127.0.0.1".split('.').new_inject(0) { |s,n| (s << 8) + n.to_i }
>
> max = (ARGV.shift || 1_000_000).to_i
>
> # # of iterations = 1000000
> #                             user     system      total        real
> # null_time               0.130000   0.000000   0.130000 (  0.129965)
> # split/each/<<          10.940000   0.010000  10.950000 ( 10.968329)
> # split/inject/<<        15.280000   0.020000  15.300000 ( 15.330062)
> # split/new_inject/<<    15.020000   0.070000  15.090000 ( 15.629343)

The question I would ask is not why does inject suck, but why doesn't  
each suck? There is only so much you can optimize in C, and you've  
really only optimized the loop -- not the arithmetic operation because  
that is yielded back to Ruby.