Closure question

  • Thread starter Fitzgerald,Greg
  • Start date
F

Fitzgerald,Greg

------_=_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?

Thanks,
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.
---------------------------------------- --
------_=_NextPart_001_01C4798D.94BA4233--
 
M

Michael Neumann

Fitzgerald said:
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 = 1
def count
proc {counter += 1}.call
end
counter
end

def create_count
counter = 0
return proc { counter += 1 }
end

counter = create_count

counter.call # => 1
counter.call # => 2
counter.call # => 3


Regards,

Michael
 
L

Lennon Day-Reynolds

Re-defining the method 'count' within its own scope won't really help;
you could do some sort of undef/def swap, but I think that's more
complexity than you really need.

To emulate an anonymous closure with no associated object instance in
Ruby, you need to use a 'proc' object bound in a context where your
counter variable is in scope.

For example:

---
def make_counter
i = 0
proc { i+=1 }
end

c = make_counter
c.call
=> 1
c[] # alias for '.call'
=> 2

d = make_counter
d[]
=> 1
 
P

Phil Tomson

------_=_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
 
P

Pit Capitain

Fitzgerald said:
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 = 1
def count
proc {counter += 1}.call
end
counter
end


I was hoping for this:
count => 1
count => 2
count => 3

Instead, I got this:
count => 1
count => NoMethodError: undefined method '+' for nil:NilClass

Hi Greg,

the inner def creates a new scope, so you can't access the counter variable from
there. Using define_method, you can avoid creating a new scope:

def count
counter = 1
self.class.send :define_method, :count do counter += 1 end
counter
end

p count # => 1
p count # => 2
p count # => 3

Regards,
Pit
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,198
Latest member
JaimieWan8

Latest Threads

Top