'static' variables in a proc?

Is there a way to get a variable in a proc that maintains it’s value
between different calls of the proc?

I tried using an instance variable:
p = proc { unless defined? @a
@a = 1
end
puts @a
@a+=1
}
#Proc:0x401bfdb0
irb(main):024:0> p.call
true
NameError: undefined method +' for true from (irb):22 from (irb):18:incall’
from (irb):24

I’m not sure why @a became true…

Then I tried:

p = proc{ unless defined? a
a = 1
end
puts a
a += 1
}

…and of course all I ever get out of it is 1, but at least a doesn’t
become ‘true’.

Phil

a = 1
p = proc {
puts a
a+=1
}

but this is different than a persistant variable, mind you. i recall that VB
has these, although i forget how they are designated. in effect you could
define procedures (methods) that would retain variable values between calls.

wonder how this is effected with the new scoping rules being talked about.

···

On Saturday 08 February 2003 10:51 pm, Phil Tomson wrote:

Is there a way to get a variable in a proc that maintains it’s value
between different calls of the proc?


tom sawyer, aka transami
transami@transami.net

Is there a way to get a variable in a proc that maintains it’s value
between different calls of the proc?

I tried using an instance variable:
p = proc { unless defined? @a
@a = 1
end
puts @a
@a+=1
}
#Proc:0x401bfdb0
irb(main):024:0> p.call
true
NameError: undefined method +' for true from (irb):22 from (irb):18:in call’
from (irb):24

I’m not sure why @a became true…

Then I tried:

p = proc{ unless defined? a
a = 1
end
puts a
a += 1
}

…and of course all I ever get out of it is 1, but at least a doesn’t
become ‘true’.

There’s a couple of ways to do it, you could just define ‘a’
outside the proc, this might suffice depending on what you’re doing:

a = 0
p = proc { a += 1; puts a}

1.upto( 3 ) {
p.call
}

a more general method would be to put ‘a’ in a singleton class:

require ‘singleton’
class MyA
include Singleton
attr_accessor :a
def initialize
@a = 0
end
end
q = proc { a = MyA.instance; a.a += 1; puts a.a}
1.upto( 3 ) {
q.call
}

···

On Sun, 9 Feb 2003 14:51:23 +0900 ptkwt@shell1.aracnet.com (Phil Tomson) wrote:

Phil


Daniel P. Zepeda

In article 200302090025.11716.transami@transami.net,

···

Tom Sawyer transami@transami.net wrote:

On Saturday 08 February 2003 10:51 pm, Phil Tomson wrote:

Is there a way to get a variable in a proc that maintains it’s value
between different calls of the proc?

a = 1
p = proc {
puts a
a+=1
}

Right, I know that would work, but it’s not exactly what I’m looking for
in this case as I might want to use the proc in several places and I would
like to have ‘a’ be different in each.

Phil

In article 200302090025.11716.transami@transami.net,

Is there a way to get a variable in a proc that maintains it’s value
between different calls of the proc?

a = 1
p = proc {
puts a
a+=1
}

[the news server seems to be having trouble, so hofefully this one will
make it]
I guess I’m looking for a function generator (maybe I’m ready for
functional programming :wink:

Why can’t I do:

#yes there are better ways of achieving the same thing

it’s a contrived example

class MyProcGen
def initialize(sv=0)
@start = sv
@p = proc { puts @start; @start += 1 }
end
attr_reader :stuck_out_tongue:
end

mpo = MyProcGen.new
mpo.p.call

?
…it doesn’t work, mpo.p is nil (Why?)

Phil

···

Tom Sawyer transami@transami.net wrote:

On Saturday 08 February 2003 10:51 pm, Phil Tomson wrote:

If it's the same Proc object then it will have no idea that it is being
called from different places, so you would have to pass in an object as a
parameter where it can store its state.

It's simpler just to generate a separate Proc object for each time you use
it, so each carries its own state:

def factory
  a = 1
  proc {
    puts a
    a = a.succ
  }
end

p1 = factory
p2 = factory
p1.call # >> 1
p1.call # >> 2
p2.call # >> 1
p2.call # >> 2

Your strangeness with '@a' was probably due to you doing previous stuff in
irb, because it works for me if I paste it into a fresh irb session:

$ irb
irb(main):001:0> p = proc { unless defined? @a
irb(main):002:2> @a = 1
irb(main):003:2> end
irb(main):004:1> puts @a
irb(main):005:1> @a+=1
irb(main):006:1> }
=> #<Proc:0x81627a0>
irb(main):007:0> p.call
1
=> 2

But the trouble with that code is, which object actually contains the
instance variable?? If I add

   puts "I am #{self.inspect}"

at the end of that proc, I get

1
I am #<Object:0x8119cd8 @a=2>

So it's not the Proc object itself, and it's not the main execution
environment (where puts self.inspect shows "main"). Too confusing... that's
why I'd recommend the Proc 'factory' instead.

The code wouldn't be affected by the new scope rules, except that you
wouldn't have to define 'a=1' before the proc. Under the current rules, if
'a=' first appears in the proc body then it is a local variable to that
proc, and gets a fresh copy each time the proc is called.

Regards,

Brian.

···

On Sun, Feb 09, 2003 at 05:31:32PM +0900, Phil Tomson wrote:

>> Is there a way to get a variable in a proc that maintains it's value
>> between different calls of the proc?
>
>a = 1
>p = proc {
> puts a
> a+=1
>}
>

Right, I know that would work, but it's not exactly what I'm looking for
in this case as I might want to use the proc in several places and I would
like to have 'a' be different in each.

I guess I'm looking for a function generator (maybe I'm ready for
functional programming :wink:

Generating functions for fun and profit :slight_smile:

  def doubler(fn)
    proc { fn.call; fn.call }
  end

  proc1 = proc { puts "hello" }
  proc2 = doubler(proc1)
  proc2.call

Why can't I do:

#yes there are better ways of achieving the same thing
# it's a contrived example
class MyProcGen
  def initialize(sv=0)
    @start = sv
    @p = proc { puts @start; @start += 1 }
  end
  attr_reader :stuck_out_tongue:
end

mpo = MyProcGen.new
mpo.p.call

?
....it doesn't work, mpo.p is nil (Why?)

Stick this in a file 'a.rb', type 'ruby a.rb', and it works for me (at least
under 1.6.8). Actually, it works under irb too:

$ irb
irb(main):001:0> class MyProcGen
irb(main):002:1> def initialize(sv=0)
irb(main):003:2> @start = sv
irb(main):004:2> @p = proc { puts self.inspect; puts @start; @start += 1 }
irb(main):005:2> end
irb(main):006:1> attr_reader :stuck_out_tongue:
irb(main):007:1> end
=> nil
irb(main):008:0>
irb(main):009:0* mpo = MyProcGen.new
=> #<MyProcGen:0x815c5a8 @p=#<Proc:0x815c580>, @start=0>
irb(main):010:0> mpo.p.call
#<MyProcGen:0x815c5a8 @p=#<Proc:0x815c580>, @start=0>
0
=> 1
irb(main):011:0> mpo.p.call
#<MyProcGen:0x815c5a8 @p=#<Proc:0x815c580>, @start=1>
1
=> 2
irb(main):012:0> mpo2 = MyProcGen.new
=> #<MyProcGen:0x8156af4 @p=#<Proc:0x8156acc>, @start=0>
irb(main):013:0> mpo2.p.call
#<MyProcGen:0x8156af4 @p=#<Proc:0x8156acc>, @start=0>
0
=> 1
irb(main):014:0> mpo2.p.call
#<MyProcGen:0x8156af4 @p=#<Proc:0x8156acc>, @start=1>
1
=> 2

Regards,

Brian.

···

On Sun, Feb 09, 2003 at 06:31:39PM +0900, Phil Tomson wrote:

figured as much, but i thought it was worth pointing out in relation to the
new scope rules in which i don’t think the initial setting will be needed.
otherwise your choices are: global variable, class variable or using the
singleton class method previously given.

···

On Sunday 09 February 2003 01:31 am, Phil Tomson wrote:

Right, I know that would work, but it’s not exactly what I’m looking for
in this case as I might want to use the proc in several places and I would
like to have ‘a’ be different in each.


tom sawyer, aka transami
transami@transami.net