static variable; behaviour in ruby?

H

Hugh Sasse

Any idea how to create or simulate a static variable in ruby?

I want to create a variable to hold state between calls of a method,
but have the state disappear when the method goes out of scope.
I could create it in some external object but then I'd need to query
the scoping rules, and know where i was.

I'm trying to do an instance_eval on a string containing a method such as
do_this x,y,z {block}
and I want to evaluate the block, or not, as a function of some
state against which x,y,z are compared. The code will be called several
times, but I only want the state intialized the first time the scope
is entered.

And, just to make matters worse, there could be several independent
calls to this method within the scope, each with its own separate
state.

Maybe there's another way to do this?

Thank you
Hugh
 
B

Brian Schröder

Any idea how to create or simulate a static variable in ruby?

I want to create a variable to hold state between calls of a method,
but have the state disappear when the method goes out of scope.
I could create it in some external object but then I'd need to query
the scoping rules, and know where i was.

I'm trying to do an instance_eval on a string containing a method such as
do_this x,y,z {block}
and I want to evaluate the block, or not, as a function of some
state against which x,y,z are compared. The code will be called several
times, but I only want the state intialized the first time the scope
is entered.

And, just to make matters worse, there could be several independent
calls to this method within the scope, each with its own separate
state.

Maybe there's another way to do this?

Thank you
Hugh

I advise that you state your basic problem, as this seems to be a
problem with an ugly workaround. You can probably restructure your
problem such that this is no longer needed.

Brian
 
P

Pit Capitain

Hugh said:
I want to create a variable to hold state between calls of a method,
but have the state disappear when the method goes out of scope.
and

And, just to make matters worse, there could be several independent
calls to this method within the scope, each with its own separate
state.

Isn't this a contradiction?

When should the state appear and when should it disappear? What should
be the scope of the state?

Regards,
Pit
 
A

Ara.T.Howard

Any idea how to create or simulate a static variable in ruby?

I want to create a variable to hold state between calls of a method,
but have the state disappear when the method goes out of scope.
I could create it in some external object but then I'd need to query
the scoping rules, and know where i was.

I'm trying to do an instance_eval on a string containing a method such as
do_this x,y,z {block}
and I want to evaluate the block, or not, as a function of some
state against which x,y,z are compared. The code will be called several
times, but I only want the state intialized the first time the scope
is entered.

And, just to make matters worse, there could be several independent
calls to this method within the scope, each with its own separate
state.

harp:~ > cat a.rb
def do_this_factory x, y, z, &block
state = rand # do something with x, y, z
lambda{ block[x, y, z] if state < 0.42 }
end

a = do_this_factory 'x','y','z' do |x,y,z| p [x,y,z] end
a.call

harp:~ > ruby a.rb

harp:~ > ruby a.rb

harp:~ > ruby a.rb
["x", "y", "z"]

harp:~ > ruby a.rb

harp:~ > ruby a.rb
["x", "y", "z"]

harp:~ > ruby a.rb
["x", "y", "z"]

Maybe there's another way to do this?

write it in assembler ;-)


-a
--
===============================================================================
| ara [dot] t [dot] howard [at] gmail [dot] com
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
H

Hugh Sasse

---559023410-351212254-1132151223=:9365
Content-Type: MULTIPART/MIXED; BOUNDARY="-559023410-351212254-1132151223=:9365"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---559023410-351212254-1132151223=:9365
Content-Type: TEXT/PLAIN; CHARSET=X-UNKNOWN
Content-Transfer-Encoding: QUOTED-PRINTABLE

=20
I advise that you state your basic problem, as this seems to be a
problem with an ugly workaround. You can probably restructure your
problem such that this is no longer needed.

I thought the paragraph about instance_eval explained it :).

Essentially, I have become fed up with lousy diagnostics from sed,
and have been trying to re-implement (enough of) it in Ruby, so I
hae some chance of getting the code to work. Thus I'd use code like:

within 10, 30 {
sub(/this/, 'that')
sub(/thingy/, 'the other')
# Example of munging something akin to C comments
within /^\s+\/\*/, /\*\/\s*$/ {
rot13 # or something
}
}

So I need to keep track of which patterns have matched, and clear
them when the scope (surrounding block) is gone.
=20
Brian
=20
Hugh
---559023410-351212254-1132151223=:9365--
---559023410-351212254-1132151223=:9365--
 
R

Robert Klemme

Hugh said:
Any idea how to create or simulate a static variable in ruby?

I completely agree to Brian's comment.
I want to create a variable to hold state between calls of a method,
but have the state disappear when the method goes out of scope.
I could create it in some external object but then I'd need to query
the scoping rules, and know where i was.

I'm not sure I understand you correctly here. Why don't you just create
an instance that holds this state plus whatever is needed and implement
your behavior in a method of that class? You can control the number of
scopes by the nuber of created instances.

Also, IMHO Pit has a valid point with his remark about a contradiction.
I'm trying to do an instance_eval on a string containing a method
such as do_this x,y,z {block}
and I want to evaluate the block, or not, as a function of some
state against which x,y,z are compared. The code will be called
several times, but I only want the state intialized the first time
the scope
is entered.

And, just to make matters worse, there could be several independent
calls to this method within the scope, each with its own separate
state.

Maybe there's another way to do this?

Did you consider using a Thread local stack for this (as I conclude from
your latest posting nesting is possible)?

Kind regards

robert
 
H

Hugh Sasse

I completely agree to Brian's comment.


I'm not sure I understand you correctly here. Why don't you just create
an instance that holds this state plus whatever is needed and implement
your behavior in a method of that class? You can control the number of

Because I can't see how to call it into being correctly. If I need
to know "when this method was called the first time" to do this,
then I need something with the same properties as a static variable,
in order to implement a thing with the same properties as a static
variable.
scopes by the nuber of created instances.

But I need to know when to create them for the string I'm
evaluating, rather than when to call on existing ones in that string.
Also, IMHO Pit has a valid point with his remark about a contradiction.

In ruby you can have several flip-flop expressions in the same
context...
Did you consider using a Thread local stack for this (as I conclude from
your latest posting nesting is possible)?

There is no concurrency in the thing at the moment, so I'm not sure
how to make use of that. Maybe it is a design pattern I've missed.

I'm beginning to think it is nontrivial, and will probably to to use
gawk to avoid sed in this case.
Kind regards

robert
Thank you,
Hugh
 
R

Robert Klemme

Hugh said:
I thought the paragraph about instance_eval explained it :).

Essentially, I have become fed up with lousy diagnostics from sed,
and have been trying to re-implement (enough of) it in Ruby, so I
hae some chance of getting the code to work. Thus I'd use code like:

within 10, 30 {
sub(/this/, 'that')
sub(/thingy/, 'the other')
# Example of munging something akin to C comments
within /^\s+\/\*/, /\*\/\s*$/ {
rot13 # or something
}
}

So I need to keep track of which patterns have matched, and clear
them when the scope (surrounding block) is gone.

Let's see whether I understand this correctly: you want your method
"within" to create something that can be later thrown against the current
line of the input and execute the given block only if the condition
matches? Wouldn't it be easier to just call within for each line of the
input?

Kind regards

robert
 
R

Robert Klemme

Hugh said:
Because I can't see how to call it into being correctly. If I need
to know "when this method was called the first time" to do this,
then I need something with the same properties as a static variable,
in order to implement a thing with the same properties as a static
variable.


But I need to know when to create them for the string I'm
evaluating, rather than when to call on existing ones in that string.

In ruby you can have several flip-flop expressions in the same
context...

There is no concurrency in the thing at the moment, so I'm not sure
how to make use of that. Maybe it is a design pattern I've missed.

I'm beginning to think it is nontrivial, and will probably to to use
gawk to avoid sed in this case.

I'm not yet convinced that it's actually so complicated. Please see my
other posting.

robert
 
H

Hugh Sasse

Any idea how to create or simulate a static variable in ruby?
[...]

harp:~ > cat a.rb
def do_this_factory x, y, z, &block
state = rand # do something with x, y, z
lambda{ block[x, y, z] if state < 0.42 }
end

a = do_this_factory 'x','y','z' do |x,y,z| p [x,y,z] end
a.call
harp:~ > ruby a.rb

harp:~ > ruby a.rb
["x", "y", "z"]
[etc]

Maybe something like
def my_method x, y, z, &block
state = rand # do something with x, y, z
alias :eek:ld_my_method, :my_method
define_method:)my_method)(x,y,z, &block)
lambda{ block[x, y, z] if state < 0.42 }.call
end
end

might do the trick, then? The state would get carried around with
the closure in subesequent calls to the same method? Except having
sevaral calls in the same block would be treated the same as severl
calls to the same method, rather than the way sed treats
/this/,/that/{ statements}, each heing independent, runnin for each
line of the input.
write it in assembler ;-)
:)
Hugh
 
H

Hugh Sasse

---559023410-1251336619-1132154331=:9365
Content-Type: MULTIPART/MIXED; BOUNDARY="-559023410-1251336619-1132154331=:9365"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---559023410-1251336619-1132154331=:9365
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN
Content-Transfer-Encoding: QUOTED-PRINTABLE

=20
Let's see whether I understand this correctly: you want your method
"within" to create something that can be later thrown against the current
line of the input and execute the given block only if the condition
matches? Wouldn't it be easier to just call within for each line of the
input?

all the statements in the input language which I'm processing with
instance_eval (for now) would be called for each line of the input.
So when each one that must hold state is called for the first time
it must clear the state, for future calls to that function on that
source line, but later input lines, it must not "cold start" the
state.=20

For within(), I'm trying to model sed's '/this/, /that/ { do_this}'
And I could have several withins in the same chunk of input
language. =20
=20
Kind regards
=20
robert
=20
Thank you,
Hugh

---559023410-1251336619-1132154331=:9365--
---559023410-1251336619-1132154331=:9365--
 
A

Ara.T.Howard

Maybe something like
def my_method x, y, z, &block
state = rand # do something with x, y, z
alias :eek:ld_my_method, :my_method
define_method:)my_method)(x,y,z, &block)
lambda{ block[x, y, z] if state < 0.42 }.call
end
end

but the second time my_method is called you'll clobber old_my_method - is that
what you want? plus it only works once because the first call to my_method
will define it in such a way that it never sets of state again - it's
clobbered by the define_method/lambda bit...
might do the trick, then? The state would get carried around with the
closure in subesequent calls to the same method? Except having sevaral
calls in the same block would be treated the same as severl calls to the
same method, rather than the way sed treats /this/,/that/{ statements}, each
heing independent, runnin for each line of the input.

i really don't quite get what you are after. but from what i'm reading it
looks alot like you would be better off doing something like this

class Line
def initialize x, y, z, &statements
@state = rand
@x, @y, @z = x, y, z
@statements = statements
end
def my_method
@statements[@x, @y, @z] if @state < 0.42
end
end

put another way - a static variable can be emulated as an instance variable of
an object. you can have multiple copies by having multiple instances. the
initialize methods makes sure it's only called once.

this might be easier?

-a
--
===============================================================================
| ara [dot] t [dot] howard [at] gmail [dot] com
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| -- bodhicaryavatara
===============================================================================
 
R

Robert Klemme

Hugh said:
all the statements in the input language which I'm processing with
instance_eval (for now) would be called for each line of the input.
So when each one that must hold state is called for the first time
it must clear the state, for future calls to that function on that
source line, but later input lines, it must not "cold start" the
state.

For within(), I'm trying to model sed's '/this/, /that/ { do_this}'
And I could have several withins in the same chunk of input
language.

I think I start getting a better understanding of your issue. How about:

def within(*a, &b)
my_state = (Thread.current[:within] || = {})[a] ||= WithinState.new(a,b)
my_state.feed(current_line)
end

If you want to make this safe against multiple invocations with similar
parameters you might use another identifying thing (possibly invoking
caller to determine source code location).

Instead of the thread local you could also use a global but IMHO this is
cleaner.

HTH

Kind regards

robert
 
H

Hugh Sasse

My use of "input" for supplied source code *and* data to process was
less than helpful. Sorry about that.
For within(), I'm trying to model sed's '/this/, /that/ { do_this}'
And I could have several withins in the same chunk of input
language.

I think I start getting a better understanding of your issue. How about:

def within(*a, &b)
my_state = (Thread.current[:within] || = {})[a] ||= WithinState.new(a,b)
my_state.feed(current_line)
end

If you want to make this safe against multiple invocations with similar
parameters you might use another identifying thing (possibly invoking
caller to determine source code location).

Yes, I was looking for that: I'd forgotten I could use caller in
something eval'd.

Making it thread local means it outlives the scope of def and is not
in the normal global namespace. That's a neat idea.
I think this will do everything I want....
Instead of the thread local you could also use a global but IMHO this is
cleaner.

HTH

Kind regards

robert
Thank you,
Hugh
 
R

Robert Klemme

Hugh said:
My use of "input" for supplied source code *and* data to process was
less than helpful. Sorry about that.
For within(), I'm trying to model sed's '/this/, /that/ { do_this}'
And I could have several withins in the same chunk of input
language.

I think I start getting a better understanding of your issue. How
about:

def within(*a, &b)
my_state = (Thread.current[:within] || = {})[a] ||=
WithinState.new(a,b) my_state.feed(current_line)
end

If you want to make this safe against multiple invocations with
similar parameters you might use another identifying thing (possibly
invoking caller to determine source code location).

Yes, I was looking for that: I'd forgotten I could use caller in
something eval'd.

Making it thread local means it outlives the scope of def and is not
in the normal global namespace. That's a neat idea.

And it's thread safe and automatically GC'ed on thread termination. :)
I think this will do everything I want....

Cool! Glad I could help.

Cheers

robert
 

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

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,260
Latest member
kentcasinohelpWilhemina

Latest Threads

Top