On Wednesday 25 November 2009 10:49:31 am Kirk Haines wrote:
> On Wed, Nov 25, 2009 at 9:29 AM, Aldric Giacomoni <aldric / trevoke.net>wrote:
> > Ralph Shnelvar wrote:
> > > y=0
> > > 1_000_000.times {|x| y+=x}
> >
> > y = (1..1_000_000).inject { |a, b| a + b }
> >
> > More idiomatic, though maybe yours is easier to read at first.
> 
> Ugh.  His, while wrong for what he is trying to do (sum from 1 to 1000000)
> is vastly superior to using inject like that.  It's not idiomatic.  It's
> obtuse.

I find this is actually significantly easier to read, though it's probably 
because I've been doing it for awhile:

(1..1_000_000).inject(&:+)

I'd much rather have a #sum method on enumerable, but that's almost as 
concise, though it takes a bit to explain why it works.

But even spelling it out, it's pretty clear if you use descriptive variables:

(1..1_000_000).inject{|sum, i| sum + i}

I don't think that's less readable, except for the fact that you have to 
understand how inject works.

> inject has no advantage with regard to
> either execution speed or object creation

But it does have the theoretical advantage of fitting exactly the map/reduce 
pattern -- inject _is_ reduce, by definition and by alias. It's overkill here, 
and I'm probably over my head, but my understanding of why map/reduce is 
efficient:

In theory, map lets you spread your dataset to up to n machines, where n is 
the number of items in your dataset, and let each machine perform whatever 
calculation was called for in the map. Once you've already done that, reduce 
makes sense -- have each machine perform the reduce (inject) function, passing 
the result to the next machine, rather than having to aggregate the result of 
the map into a single location.

In reality, none of this really applies to Ruby, at least not to the standard 
map/inject methods. But it's worth thinking about, and probably good practice 
for the manycore monstrosities of the future.