Inject is pathetic?

What do you mean by that?

-Dave

···

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.

--
Dave Aronson, Available Secret-Cleared Ruby/Rails Freelancer (VA/DC/Remote);
see www.DaveAronson.com, www.Codosaur.us, and www.Dare2XL.com for more info.

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(:+)

Not everyone knows LISP or has read The Structure and Interpretation of
Computer Programs. Those who have, know. m.

···

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?

--
matt neuburg, phd = matt@tidbits.com <http://www.tidbits.com/matt/&gt;
A fool + a tool + an autorelease pool = cool!
AppleScript: the Definitive Guide - Second Edition!
Matt Neuburg’s Home Page

Agree. #inject is essential for Array.

···

On Sep 14, 2012, at 11:00 AM, Matt Neuburg 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(:+)

Not everyone knows LISP or has read The Structure and Interpretation of
Computer Programs. Those who have, know. m.

--
matt neuburg, phd = matt@tidbits.com <http://www.tidbits.com/matt/&gt;
A fool + a tool + an autorelease pool = cool!
AppleScript: the Definitive Guide - Second Edition!
Matt Neuburg’s Home Page

Best regards,
Zhi-Qiang Lei
zhiqiang.lei@gmail.com

>
> > 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).

···

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:

but josh, isn't that because of String#+ ?

there is always String#<< or String#concat.

nonetheless, am also a fan of inject syntax, and hope to see someday,
a more super fast version of inject. The inject syntax is stupidly
generic/flexible, that is why many luv it, including me :wink:

btw, i usually use each.with_object instead of each_with_object. And i
alias with_object to using_object. but hey, that is just me. but
regardless, we all are fan of ruby, right? to each, his each, i guess
:wink:

kind regards -botp

···

On Fri, Sep 14, 2012 at 5:46 PM, Josh Cheek <josh.cheek@gmail.com> wrote:

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

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

Josh Cheek wrote in post #1075977:

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"

Correct, in ruby, because ruby isn't optimised for funtional use.
Another example is that there is no tail-recursion unless you build ruby
with a special compile-time option.

But in other languages, what you've written is actually efficient. For
example, Erlang has a specific optimisation for binaries which are
appended to, where no reference remains to the previous incarnation of
the binary.

Your example is compelling to you, because you're enamored with the
implementation

I'd say the opposite; in ruby the implementation is not so good, but
it's the concept, the abstraction, which is attractive.

foo.each => do something for each element of an array
foo.inject => calculate a summary value across all elements of an array

In fully functional languages, foo.each makes no sense because "do
something" makes no sense - functions don't have side-effects. (Erlang
is *not* such a language, by the way, but is part way because it doesn't
have mutable variables).

···

--
Posted via http://www.ruby-forum.com/\.

> strings.inject("") { |joined, current| joined + current }
>
> is slow and wasteful because it created all the intermediate forms: "",
"a",
> "ab", "abc", "abcd", "abcde"

but josh, isn't that because of String#+ ?

Yes

there is always String#<< or String#concat.

You're right, since String#<< returns self, you can do it efficiently with
inject:

[*'a'..'e'].inject('', :<<) # => "abcde"

Instead of

[*'a'..'e'].inject('', :+) # => "abcde"

It deviates from the more functional ideas of immutable data, which is
where inject makes the most sense, but in Ruby this case will work
sufficiently.

When return values don't match up nicely like this, it gets cumbersome
(you have to go to multiple lines or use semicolons):

%w[a b a c].inject(Hash.new 0) { |sums, char| sums[char] += 1; sums }
%w[a b a c].each_with_object(Hash.new 0) { |char, sums| sums[char] += 1 }

btw, i usually use each.with_object instead of each_with_object. And i
alias with_object to using_object. but hey, that is just me. but
regardless, we all are fan of ruby, right? to each, his each, i guess
:wink:

I only do .with_object when I'm working with an arbitrary enumerator,
because I expect it has overhead associated with its laziness. I don't know
how it is implemented (it takes a lot of effort for me to figure out what C
Ruby is doing), but I think of it basically like this:

List = Struct.new :element, :child do
  def each_with_object(object, &block)
    block[element, object]
    child && child.each_with_object(object, &block)
    object
  end

  def each(&block)
    return LazyIteration.new self, :each unless block
    block[element]
    child && child.each(&block)
  end

  LazyIteration = Struct.new :target, :message do
    def with_object(object, &block)
      target.send(message) { |element| block[element, object] }
      object
    end
  end
end

list = List.new('a', List.new('b', List.new('c', nil)))

list.each_with_object('') { |element, aggregate| aggregate << element } #
=> "abc"
list.each.with_object('') { |element, aggregate| aggregate << element } #
=> "abc"

···

On Fri, Sep 14, 2012 at 5:19 AM, botp <botpena@gmail.com> wrote:

On Fri, Sep 14, 2012 at 5:46 PM, Josh Cheek <josh.cheek@gmail.com> wrote:

Correct, in ruby, because ruby isn't optimised for funtional use.

Interesting. Will it be?

Best regards,
Zhi-Qiang Lei
zhiqiang.lei@gmail.com

I strongly doubt it, there's too much OO in the core for the language
to ever lean very far in a stateless (functional) direction.

···

On 16 September 2012 14:41, Zhi-Qiang Lei <zhiqiang.lei@gmail.com> wrote:

Correct, in ruby, because ruby isn't optimised for funtional use.

Interesting. Will it be?

--
  Matthew Kerwin, B.Sc (CompSci) (Hons)
  http://matthew.kerwin.net.au/
  ABN: 59-013-727-651

  "You'll never find a programming language that frees
  you from the burden of clarifying your ideas." - xkcd

FP and OO are not orthogonal. Perhaps the word you were looking for was
"mutation"

···

On Sun, Sep 16, 2012 at 1:00 AM, Matthew Kerwin <matthew@kerwin.net.au>wrote:

I strongly doubt it, there's too much OO in the core for the language
to ever lean very far in a stateless (functional) direction.

--
Tony Arcieri