Closure question

>I'm trying to make a function act as a counter, but I can't
seem to get
>it to work. Here's what I've tried:
>
>def count
> counter =3D 1
> def count
> proc {counter +=3D 1}.call
> end
> counter
>end
>
>
>I was hoping for this:
>count =3D> 1
>count =3D> 2
>count =3D> 3
>
>Instead, I got this:
>count =3D> 1
>count =3D> NoMethodError: undefined method '+' for nil:NilClass
>
>Isn't the idea of a closure that everything in the block is
executed in
>the same scope it was defined? It seems that the name 'counter' is
>referenced under the name 'count', and so when I redefine
'count', the
>'counter' variable gets lost. Anyone know what's really
happening here?
>

The problem is that you've defined a new scope with the
definition of the inner 'count' method, so the 'counter'
variable you're referring to inside of the proc is not the
same as the one defined in the outer count method.
Also, everytime you call 'count', doesn't the 'counter'
variable get reinitialized to '1'? And, it's not clear to me
how the inner 'count'
method would ever get called. I believe you're seeing the
error because both the inner and the outer 'count' methods
are both called 'count'.

I modified your code somewhat to remove the name collision:

irb(main):064:0> def foo
irb(main):065:1> counter = 1
irb(main):066:1> def bar
irb(main):067:2> proc {counter += 1}.call
irb(main):068:2> end
irb(main):069:1> bar #-> note this added call to bar
irb(main):070:1> counter
irb(main):071:1> end
=> nil
irb(main):072:0> foo
NoMethodError: undefined method `+' for nil:NilClass
  from (irb):67:in `bar'
  from (irb):67:in `call'
  from (irb):67:in `bar'
  from (irb):69:in `foo'
  from (irb):72
  from :0

.... so the inner method, bar, knows nothing about the
'counter' variable defined in the outer scope.

Here's how I'd do a counter, but it doesn't involve closures,
so maybe it
doesn't address your question:

class Counter
  def initialize
    @counter = 1
  end

  def count
    @counter += 1
  end
end

cc = Counter.new
cc.count #=> 2
cc.count #=> 3

Phil

Jim and Pit hit the nail on the head with:

def count
  counter = 1
  self.class.send(:define_method, :count) { counter += 1 }
  counter
end

The idea is to redefine the 'count' function so that after it is called
the first time, the line 'counter = 1' is never executed again.
Instead, when 'count' is called, only 'counter += 1' is executed. The
new 'count' function will now reference the original 'counter' variable
that existed at the time the closure was created. Good fun.

-Greg

CONFIDENTIALITY NOTICE

This message and any included attachments
are from Cerner Corporation and are intended
only for the addressee. The information
contained in this message is confidential and
may constitute inside or non-public information
under international, federal, or state
securities laws. Unauthorized forwarding,
printing, copying, distribution, or use of such
information is strictly prohibited and may be
unlawful. If you are not the addressee, please
promptly delete this message and notify the
sender of the delivery error by e-mail or you
may call Cerner's corporate offices in Kansas
City, Missouri, U.S.A at (+1) (816)221-1024.
---------------------------------------- --