Each iterator passing in nil

Hi all,

In Rails console (just doing a general exercise in ruby design
patterns), I create two classes:

ruby-1.9.2-p136 :023 > class A
ruby-1.9.2-p136 :024?> attr_accessor :name, :balance
ruby-1.9.2-p136 :025?> def initialize(name, balance)
ruby-1.9.2-p136 :026?> @name = name
ruby-1.9.2-p136 :027?> @balance = balance
ruby-1.9.2-p136 :028?> end
ruby-1.9.2-p136 :029?> def <=>(other)
ruby-1.9.2-p136 :030?> balance <=> other.balance
ruby-1.9.2-p136 :031?> end
ruby-1.9.2-p136 :032?> end
=> nil
ruby-1.9.2-p136 :033 > class Portfolio
ruby-1.9.2-p136 :034?> include Enumerable
ruby-1.9.2-p136 :035?> def initialize
ruby-1.9.2-p136 :036?> @accounts = []
ruby-1.9.2-p136 :037?> end
ruby-1.9.2-p136 :038?> def each(&block)
ruby-1.9.2-p136 :039?> @accounts.each(&block)
ruby-1.9.2-p136 :040?> end
ruby-1.9.2-p136 :041?> def add_account(account)
ruby-1.9.2-p136 :042?> @accounts << account
ruby-1.9.2-p136 :043?> end
ruby-1.9.2-p136 :044?> end
=> nil

client code:
ruby-1.9.2-p136 :045 > portfolio = Portfolio.new
=> #<Portfolio:0x00000105d47118 @accounts=[]>
ruby-1.9.2-p136 :091 > a = A.new(‘n’,1000)
=> #<A:0x00000105fdc478 @name=“n”, @balance=1000>
ruby-1.9.2-p136 :092 > portfolio.add_account(a)
=> [#<A:0x00000105fdc478 @name=“n”, @balance=1000>]
ruby-1.9.2-p136 :093 > b = A.new(‘b’,2000)
=> #<A:0x00000105fd0ba0 @name=“b”, @balance=2000>
ruby-1.9.2-p136 :094 > portfolio.add_account(b)
=> [#<A:0x00000105fdc478 @name=“n”, @balance=1000>, #<A:
0x00000105fd0ba0 @name=“b”, @balance=2000>]
ruby-1.9.2-p136 :095 > portfolio.each {|n, b| n <=> b }
NoMethodError: undefined method `balance’ for nil:NilClass

It appears that the each iterator does not support passing in two
arguments? because I expect n to be object 0x00000105fdc478 and I
expect b to be object 0x00000105fd0ba0. Then I expect once the each
iterator of portfolio is called and executed, we in turn call each on
the array of accounts, passing in our block. When that call occurs, we
invoke the defined <=> instance method of A class, passing in the two
objects stored in @accounts. This in turn will call the <=> method of
enumerable and perform comparison operation. However, what I just
described above does not occur.

thanks for response

John M. wrote in post #1029066:

client code:
ruby-1.9.2-p136 :095 > portfolio.each {|n, b| n <=> b }

You obviously aren’t quite understanding what block actually are.

NoMethodError: undefined method `balance’ for nil:NilClass
Well yea. The block that gets passed into each was designed to take one
argument.

Each is a block (a.k.a closure, a.k.a lambda function, a.k.a anonymous
function) that has a design similar to any regular method or function,
for example:

def each(arg) do

method body

end

If you were to pass two arguments to that method you’d have a similar
result:

self.each(a, b)
=> Results in something just as nasty.

On Sat, Oct 29, 2011 at 00:09, John M. [email protected] wrote:

ruby-1.9.2-p136 :095 > portfolio.each {|n, b| n <=> b }
NoMethodError: undefined method `balance’ for nil:NilClass

It appears that the each iterator does not support passing in two
arguments?

Correct. “each” means “apply this block to each of this collection’s
elements in turn”, not “… in parallel”. Otherwise you’d have to
have the block accept exactly as many args as there are elements. (Or
of course accept a collection, in which case you’re back to square
one.)

-Dave


LOOKING FOR WORK! What: Ruby (on/off Rails), Python, other modern
languages.
Where: Northern Virginia, Washington DC (near Orange Line), and remote
work.
See: davearonson.com (main) * codosaur.us (code) * dare2xl.com
(excellence).
Specialization is for insects. (Heinlein) - Have Pun, Will Babble!
(Aronson)

On Sun, Oct 30, 2011 at 21:09, John M. [email protected] wrote:

I need more time of my own to investigate a better way to do this.

Maybe we can still help. What were you trying to accomplish with the
code that failed:

portfolio.each {|n, b| n <=> b }

?

Were you trying to sort them? Maybe you could just delegate that to
accounts.

-Dave


LOOKING FOR WORK! What: Ruby (on/off Rails), Python, other modern
languages.
Where: Northern Virginia, Washington DC (near Orange Line), and remote
work.
See: davearonson.com (main) * codosaur.us (code) * dare2xl.com
(excellence).
Specialization is for insects. (Heinlein) - Have Pun, Will Babble!
(Aronson)

thanks for responses, it makes sense that it failed, because the each
iterator is only intended to iterate over one object at a time. I need
more time of my own to investigate a better way to do this.

On Oct 29, 2:28pm, Dave A. [email protected]