On Thu, Sep 13, 2012 at 10:00 PM, Matt Neuburg <matt / tidbits.com> wrote:

> Dave Aronson <rubytalk2dave / davearonson.com> wrote:
>
> > On Wed, Sep 12, 2012 at 11:46 PM, 7stud -- <lists / ruby-forum.com> wrote:
> >
> > > Just forget inject() even exists.  It's really quite a pathetic method.
> >
> > What do you mean by that?
>
> He probably just doesn't grasp how fundamental it is. After all, no one
> would call "join" pathetic, but it is simply a special case of inject.
> Or, to put it a better way, inject abstracts intuitively obvious notions
> such as join, sum, and product. And in Ruby 1.9.3 it gets even cooler,
> since you can just say:
>
>    [1,2,3].inject(:+)
>
>
I disagree. Nearly everything you want to use inject for, each_with_object
is better. Array#join, for example is better implemented using
each_with_object than inject

strings.each_with_object("") { |current, joined| joined << current }

Perhaps in a language like Haskell where strings are just lists of
characters, then you could join them in a single pass, if you started at
the end and worked backwards. Or perhaps the thunk could be smart enough to
compose or allow access to it without creating all the intermediate forms.
But in Ruby

strings.inject("") { |joined, current| joined + current }

is slow and wasteful because it created all the intermediate forms: "",
"a", "ab", "abc", "abcd", "abcde"
Whereas each_with_object only creates: "abcde"



Your example is compelling to you, because you're enamored with the
implementation, but `[1,2,3].inject(:+)` is ugly, confusing, and buggy. If
we could say something like `[1,2,3].sum_from 0`, this would be clearer
because we don't care about the implementation. When we see `.inject(:+)`
we have to mentally translate it "oh, we're getting the sum". That cost
adds up, things like this should be declarative. It's buggy because if your
array is empty, you get `[].inject(:+) # => nil`, but the null object for a
sum is 0, so you have to remember to pass the initial argument
`[].inject(0, :+) # => 0` (that param should probably be required). It's
further ugly because it breaks from Ruby conventions. When you have a
method that takes a block, everywhere else you would have to say
`[].inject(0, &:+)`, but here, translating the symbol into a block is moved
into the method, causing you to think you have a bug until you go read the
docs enough times to remember this one-off case.

And in the few cases where inject does make more sense than
each_with_object, it may be clearer to just iterate over the array with
#each, and update a local variable.



> Not everyone knows LISP or has read The Structure and Interpretation of
> Computer Programs. Those who have, know. m.
>
>
I generally like Lisp, but the elitism around it is just obnoxious, as in
this quote (at least for Common Lisp and Scheme, Clojure seems more down to
earth).