Dynamically scoped variables

Just as a bit of fun I posted a piece on implementing dynamically scoped
variables in Ruby at

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc,v

I’m sure there are easier ways. I just hacked this one out, so I’m happy
to be humiliated with better solutions.

Cheers

Dave

Dave Thomas wrote:

Just as a bit of fun I posted a piece on implementing dynamically scoped
variables in Ruby at

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc,v

Very cool!

Here’s a variant that lets you access local variables from nested
dynamic scopes, though I’m not sure that’s a good idea :slight_smile:

def with_current_context
finder = catch(:context) { yield }
finder.call(Proc.new.binding) if finder
## ? Is there an easier way to get caller’s binding?
end

def find_in_context(name)
callcc do |again|
throw(:context,
proc {|b|
begin
val = eval(name, b)
again.call(val)
rescue NameError
raise “Can’t find context value for #{name}”
end
})
end
end

def update_widget
name = find_in_context(“name”)
color = find_in_context(“color”)
puts “<#{color}>#{name}</#{color}>”
end

def update_screen
update_widget
end

name = ‘dave’; color = ‘red’
with_current_context do
update_screen
end

Dave Thomas wrote:

Just as a bit of fun I posted a piece on implementing dynamically scoped
variables in Ruby at

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc,v

And, a variant that allows nested contexts to be cumulative, at the cost
of an additional outer wrapper around code that uses it.

def with_context(params)
finder, = catch(:context) { yield }
finder.call(params) if finder
end

def find_in_context(name)
callcc do |again|
throw(:context, [proc {|params|
if params.has_key?(name)
again.call(params[name])
else
again.call(find_in_context(name))
end
}, name])
end
end

def use_dynamic_biding
attempt, name = catch(:context) { yield }
if attempt
raise “Can’t find context value for #{name}”
end
end

def update_widget
name = find_in_context(:name)
color = find_in_context(:color)
puts “<#{color}>#{name}</#{color}>”
end

def update_screen
update_widget
end

use_dynamic_biding do
with_context(:name => ‘dave’, :color => ‘red’) do
with_context(:foo => ‘bar’) do
update_screen
end
end
end

In article 3EDC224D.90803@pragprog.com,
Dave Thomas dave@pragprog.com writes:

Just as a bit of fun I posted a piece on implementing dynamically scoped
variables in Ruby at

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc,v

I’m sure there are easier ways. I just hacked this one out, so I’m happy
to be humiliated with better solutions.

def with_context(params)
Thread.current[:dynamic] ||=
Thread.current[:dynamic].push params
begin
yield
ensure
Thread.current[:dynamic].pop
end
end

def find_in_context(name)
Thread.current[:dynamic].reverse_each {|params|
return params[name] if params.has_key? name
}
raise “Can’t find context value for #{name}”
end

···


Tanaka Akira

“Tanaka Akira” akr@m17n.org schrieb im Newsbeitrag
news:87k7c3mxma.fsf@serein.a02.aist.go.jp…

In article 3EDC224D.90803@pragprog.com,
Dave Thomas dave@pragprog.com writes:

Just as a bit of fun I posted a piece on implementing dynamically
scoped
variables in Ruby at

http://pragprog.com/pragdave/Tech/Random/StackContext.rdoc,v

I’m sure there are easier ways. I just hacked this one out, so I’m
happy
to be humiliated with better solutions.

def with_context(params)
Thread.current[:dynamic] ||=
Thread.current[:dynamic].push params
begin
yield
ensure
Thread.current[:dynamic].pop
end
end

def find_in_context(name)
Thread.current[:dynamic].reverse_each {|params|
return params[name] if params.has_key? name
}
raise “Can’t find context value for #{name}”
end

Very nice indeed! Couldn’t we save one lookup by doing

def with_context(params)
( Thread.current[:dynamic] ||= ).push params
begin
yield
ensure
Thread.current[:dynamic].pop
end
end

Regards

robert