returning symbols

D

Daniel Cremer

I want to write a method to store a list of some instance variables in
an Array that will later be run through to access their data. Normally
in another language I would do this by passing them by reference when I
store them into the Array.

Using the object_id doesn't work because that's to the object the
variable is pointing to and this may change.
So, to sum it up:

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

thanks,
Daniel
 
D

Dave Thomas

Is there a way to get variables to return their symbol so you can
access
what they will be referencing in the future ?

You could use a closure, but more typically you'd want to enapsulate he
set of variables into a class and return that class.


Cheers

Dave
 
K

Kristof Bastiaensen

Hi,

I want to write a method to store a list of some instance variables in an
Array that will later be run through to access their data. Normally in
another language I would do this by passing them by reference when I store
them into the Array.

Using the object_id doesn't work because that's to the object the variable
is pointing to and this may change. So, to sum it up:

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

thanks,
Daniel

You can use the name as a string or symbol, and retrieve
the value with instance_variable_get.
ri instance_variable_get


------------------------------------------- Object#instance_variable_get
obj.instance_variable_get(symbol) => obj
------------------------------------------------------------------------
Returns the value of the given instance variable (or throws a
NameError exception). The @ part of the variable name should be
included for regular instance variables

class Fred
def initialize(p1, p2)
@a, @b = p1, p2
end
end
fred = Fred.new('cat', 99)
fred.instance_variable_get:)@a) #=> "cat"
fred.instance_variable_get("@b") #=> 99

Cheers,
KB
 
M

Mikael Brockman

Daniel Cremer said:
I want to write a method to store a list of some instance variables in
an Array that will later be run through to access their data. Normally
in another language I would do this by passing them by reference when I
store them into the Array.

Using the object_id doesn't work because that's to the object the
variable is pointing to and this may change.
So, to sum it up:

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

thanks,
Daniel

It's kind of a hack, and you should avoid using it, but

| class Box
| def initialize (&accessor)
| @accessor = accessor
| end
|
| def set! (new)
| @accessor.call new
| end
|
| def get
| @accessor.call
| end
| end
|
| class Object
| def box (variable)
| Box.new do |*value|
| if value.empty?
| instance_variable_get variable
| else
| instance_variable_set variable, value.first
| end
| end
| end
| end
foo = Foo.new
=> # said:
box = foo.box:)@a)
=> # said:
box.get => 5
box.set! 10 => 10
box.get => 10
foo.instance_variable_get:)@a)
=> 10
 
T

T. Onoma

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

class C
attr_accessor :a, :b, :c
def initialize
@a, @b, @c = 1, 2, 3
end
def bump
@a, @b, @c = 100, 200, 300
end
def ref
return [ lambda { @a }, lambda { @b }, lambda { @c } ]
end
end

c = C.new
v = c.ref
v.each { |q| puts q.call }
c.bump
v.each { |q| puts q.call }
 
D

Daniel Cremer

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

class C
attr_accessor :a, :b, :c
def initialize
@a, @b, @c = 1, 2, 3
end
def bump
@a, @b, @c = 100, 200, 300
end
def ref
return [ lambda { @a }, lambda { @b }, lambda { @c } ]
end
end

c = C.new
v = c.ref
v.each { |q| puts q.call }
c.bump
v.each { |q| puts q.call }

Interesting example... What I don't understand is how would you
implement object pools in Ruby ? If I understand correctly with object
pools you often have data representing state stored separately. Then
when needed you can grab an instance of the object from the pool and
populate it with this data.
For an example like that I would like to have a base-class that
implements a persist() method. This way developers working on a class
can inherit this class and simply pass the objects representing state to
this persist() method.

def persist(*state_objs)
...
persistent_objects = Array.new()
state_objs.each { |obj| persistent_objects << obj }
...
end
From then on it could be included into object pools with no further work
from the developer.

But this is were I have problems. Implementing this in the base class
such that it can take any list of variables without any knowledge of
their names and being able to get back to the contents of the variables
to store the state before returning the object to the pool.
I hope this makes sense, I might be confusing myself :)

You could use a closure, but more typically you'd want to enapsulate he
set of variables into a class and return that class.

Could someone elaborate on the part about returning a class. I'm not
sure if I captured the full meaning.

thanks,
Daniel
 
F

Florian Gross

Daniel said:
Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

For ordinary variables you can use the code that I attached.
thanks,
Daniel

Regards,
Florian Gross

require 'binding_of_caller'

class Variable
def self.new(name, context = nil)
return super(name, context) unless context.nil?
Binding.of_caller do |context|
super(name, context)
end
end
class << self; alias :[] :new; end

attr_reader :context, :name

def initialize(name, context)
unless /^[a-z_][\w\d_]*$/.match(name.to_s)
raise(NameError, "Illegal variable name: #{name.inspect}")
end

@name, @context = name, context
@setter = lambda do |value|
eval "#{@name} = ObjectSpace._id2ref(#{value.id})", context
end
exists = lambda do
eval "local_variables.include?(#{@name.to_s.inspect})", context
end
@getter = lambda do
eval("#{@name}", context) if exists.call
end
end

def []=(value); @setter.call(value); end
def []; @getter.call; end
alias :value= :[]=
alias :value :[]

def inspect
"Variable[#{@name.inspect}, #{@context.inspect}]"
end
end

begin
require 'simplecc'
rescue LoadError
def Continuation.create(*args, &block)
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
result ||= args
return *[cc, *result]
end
end

# This method returns the binding of the method that called your
# method. It will raise an Exception when you're not inside a method.
#
# It's used like this:
# def inc_counter
# Binding.of_caller do |binding|
# eval("counter += 1", binding)
# end
# end
# counter = 0
# 2.times { inc_counter }
# counter # => 2
#
# You will have to put the whole rest of your method into the
# block that you pass into this method. If you don't do this
# an Exception will be raised. Because of the way that this is
# implemented it has to be done this way. If you don't do it
# like this it will raise an Exception.
def Binding.of_caller(&block)
old_critical = Thread.critical
Thread.critical = true
count = 0
cc, result, error = Continuation.create(nil, nil)
error.call if error

tracer = lambda do |*args|
type, context = args[0], args[4]
if type == "return"
count += 1
# First this method and then calling one will return --
# the trace event of the second event gets the context
# of the method which called the method that called this
# method.
if count == 2
# It would be nice if we could restore the trace_func
# that was set before we swapped in our own one, but
# this is impossible without overloading set_trace_func
# in current Ruby.
set_trace_func(nil)
cc.call(eval("binding", context), nil)
end
elsif type != "line"
set_trace_func(nil)
error_msg = "Binding.of_caller used in non-method context or " +
"trailing statements of method using it aren't in the block."
cc.call(nil, lambda { raise(ArgumentError, error_msg ) })
end
end

unless result
set_trace_func(tracer)
return nil
else
Thread.critical = old_critical
yield result
end
end
 
A

Ara.T.Howard

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

class C
attr_accessor :a, :b, :c
def initialize
@a, @b, @c = 1, 2, 3
end
def bump
@a, @b, @c = 100, 200, 300
end
def ref
return [ lambda { @a }, lambda { @b }, lambda { @c } ]
end
end

c = C.new
v = c.ref
v.each { |q| puts q.call }
c.bump
v.each { |q| puts q.call }

what does this give you over this?

~ > cat a.rb
class C
VARS = :a, :b, :c
VARS.each{|v| attr_accessor v}
def initialize
@a, @b, @c = 1, 2, 3
end
def bump
@a, @b, @c = 100, 200, 300
end
def ref
VARS
end
end

c = C.new
vars = c.ref
vars.each { |v| puts(c.send(v)) }
c.bump
vars.each { |v| puts(c.send(v)) }


~ > ruby a.rb
1
2
3
100
200
300


what am i missing here?

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
T

T. Onoma

what does this give you over this?
...
what am i missing here?

Reference to c. With the lambda example the context is embedded. Send on the
other hand requires the applicable object be remembered separately.

vars.each { |q| puts q.call } # no c
vars.each { |v| puts(c.send(v)) }
 
D

Daniel Cremer

... What I don't understand is how would you
implement object pools in Ruby ? If I understand correctly with object
pools you often have data representing state stored separately. Then
when needed you can grab an instance of the object from the pool and
populate it with this data.
For an example like that I would like to have a base-class that
implements a persist() method. This way developers working on a class
can inherit this class and simply pass the objects representing state to
this persist() method.

def persist(*state_objs)
...
persistent_objects = Array.new()
state_objs.each { |obj| persistent_objects << obj }
...
end

from the developer.

But this is were I have problems. Implementing this in the base class
such that it can take any list of variables without any knowledge of
their names and being able to get back to the contents of the variables
to store the state before returning the object to the pool.
I hope this makes sense, I might be confusing myself :)

Ok I think I cleared my brain a bit on my particular example and did a
quick implementation:

--------------------------------
require 'set'

class MyBaseClass
@@persist = Set.new()

def MyBaseClass.persist(*symbol)
symbol.each do |symbol|
instance_symbol = "@" + symbol.to_s
@@persist.add(instance_symbol)
end
end

def return_persistent_vars()
output = Array.new()
@@persist.each {|val| output << self.instance_variable_get(val) }
return output
end
end


class ObjPoolObj < MyBaseClass
attr_accessor :var1, :var2, :var3
persist :var1, :var2

def initialize
@var1 = "hello"
@var2 = "world"
@var3 = "nothingHere"
end

end

test_obj = ObjPoolObj.new()
puts test_obj.return_persistent_vars() #=> hello
#=> world

test_obj.var1 = "hellomodified"
puts test_obj.return_persistent_vars() #=> hellomodified
#=> world

---------------------------

The part I find cool is being able to call: "persist :var1, :var2" in
the same manner as attr_accessor. Of course the whole storing of the
data and stuffing it back into the object from the pool would need to be
implemented but that should be simple enough. I'll think about
generalising this stuff...
thanks for keeping my neurons firing.
Daniel
 
R

Robert Klemme

Daniel Cremer said:
I want to write a method to store a list of some instance variables in
an Array that will later be run through to access their data. Normally
in another language I would do this by passing them by reference when I
store them into the Array.

Using the object_id doesn't work because that's to the object the
variable is pointing to and this may change.
So, to sum it up:

Is there a way to get variables to return their symbol so you can access
what they will be referencing in the future ?

If I do understand correctly you want to store "self" together with the
information which members of "self" to retrieve. Others presented solutions
already, here is another one that is similar to the closure approach in that
it uses an array of elements that store "self" and an accessor for a certain
value but uses method instances instead:

class Foo
attr_accessor :bar, :baz, :name
end

f = Foo.new

accessors = [:bar, :baz, :name].map { |s| f.method s }

p accessors.map { |acc| acc.call }

f.bar = "bar"
f.baz = "baz"
f.name = "name"

p accessors.map { |acc| acc.call }

f.bar = "BAR"
f.baz = "BAZ"
f.name = "NAME"

p accessors.map { |acc| acc.call }

Dunno which is more efficient though.

Kind regards

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,755
Messages
2,569,536
Members
45,010
Latest member
MerrillEic

Latest Threads

Top