From: ptkwt@... (Phil Tomson) Date: 2004-08-04T05:21:32+09:00 Subject: Re: Closure question In article <25820D5115DEEB48AC514130CA7BA29355F85A@MSMBWHQ05.northamerica.cerner.net>, Fitzgerald,Greg wrote: >------_=_NextPart_001_01C4798D.94BA4233 >Content-Type: text/plain; > charset="us-ascii" >Content-Transfer-Encoding: quoted-printable > > >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