Inject is pathetic?

On Wed, Sep 12, 2012 at 11:46 PM, 7stud – [email protected] wrote:

Just forget inject() even exists. It’s really quite a pathetic method.

What do you mean by that?

-Dave

Dave A. [email protected] wrote:

On Wed, Sep 12, 2012 at 11:46 PM, 7stud – [email protected] 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.

Agree. #inject is essential for Array.

On Sep 14, 2012, at 11:00 AM, Matt N. wrote:

Or, to put it a better way, inject abstracts intuitively obvious notions
A fool + a tool + an autorelease pool = cool!
AppleScript: the Definitive Guide - Second Edition!
Matt Neuburg’s Home Page

Best regards,
Zhi-Qiang L.
[email protected]

On Fri, Sep 14, 2012 at 5:46 PM, Josh C. [email protected]
wrote:

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#+ ?

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:19 AM, botp [email protected] wrote:

On Fri, Sep 14, 2012 at 5:46 PM, Josh C. [email protected] wrote:

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”

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

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

Interesting. Will it be?

Best regards,
Zhi-Qiang L.
[email protected]

On 16 September 2012 14:41, Zhi-Qiang L. [email protected]
wrote:

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

Interesting. Will it be?

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.


Matthew K., 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

On Sun, Sep 16, 2012 at 1:00 AM, Matthew K.
[email protected]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.

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

On Thu, Sep 13, 2012 at 10:00 PM, Matt N. [email protected] wrote:

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