returning symbols

Discussion in 'Ruby' started by Daniel Cremer, Aug 16, 2004.

  1. 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
     
    Daniel Cremer, Aug 16, 2004
    #1
    1. Advertising

  2. Daniel Cremer

    Dave Thomas Guest

    On Aug 16, 2004, at 7:47, Daniel Cremer wrote:
    > 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
     
    Dave Thomas, Aug 16, 2004
    #2
    1. Advertising

  3. Hi,

    On Mon, 16 Aug 2004 21:47:59 +0900, Daniel Cremer wrote:

    > 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
     
    Kristof Bastiaensen, Aug 16, 2004
    #3
  4. Daniel Cremer <> writes:

    > 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

    => #<Foo:0x402f94c4 @a=5>
    > box = foo.box:)@a)

    => #<Box:0x402f68dc @accessor=#<Proc:0x4030f530@./boxes.rb:18>>
    > box.get

    => 5
    > box.set! 10

    => 10
    > box.get

    => 10
    > foo.instance_variable_get:)@a)

    => 10
     
    Mikael Brockman, Aug 16, 2004
    #4
  5. Daniel Cremer

    T. Onoma Guest

    On Monday 16 August 2004 08:47 am, Daniel Cremer wrote:
    > 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 }

    --
    T.
     
    T. Onoma, Aug 16, 2004
    #5
  6. On Mon, 2004-08-16 at 14:53, T. Onoma wrote:
    > On Monday 16 August 2004 08:47 am, Daniel Cremer wrote:
    > > 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 :)

    On Mon, 2004-08-16 at 14:04, Dave Thomas wrote:
    > 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
     
    Daniel Cremer, Aug 16, 2004
    #6
  7. Daniel Cremer wrote:

    > 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
     
    Florian Gross, Aug 16, 2004
    #7
  8. Daniel Cremer

    Ara.T.Howard Guest

    On Mon, 16 Aug 2004, T. Onoma wrote:

    > On Monday 16 August 2004 08:47 am, Daniel Cremer wrote:
    >> 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 }
    >
    > --
    > T.


    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
    ===============================================================================
     
    Ara.T.Howard, Aug 16, 2004
    #8
  9. Daniel Cremer

    T. Onoma Guest

    On Monday 16 August 2004 10:51 am, Ara.T.Howard wrote:
    > 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)) }

    --
    T.
     
    T. Onoma, Aug 16, 2004
    #9
  10. On Mon, 2004-08-16 at 15:23, Daniel Cremer wrote:
    > ... 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 :)


    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
     
    Daniel Cremer, Aug 16, 2004
    #10
  11. "Daniel Cremer" <> schrieb im Newsbeitrag
    news:...
    > 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
     
    Robert Klemme, Aug 16, 2004
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?QUs=?=

    Debug symbols not for all .aspx forms.

    =?Utf-8?B?QUs=?=, Jan 19, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    910
    Habib Heydarian [MSFT]
    Jan 23, 2004
  2. Gibs

    Displaying Special Symbols

    Gibs, Jun 29, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    472
    Ken Cox [Microsoft MVP]
    Jun 29, 2004
  3. Brian Henry

    <% symbols

    Brian Henry, Jul 6, 2004, in forum: ASP .Net
    Replies:
    5
    Views:
    588
    clintonG
    Jul 6, 2004
  4. Shawn South
    Replies:
    0
    Views:
    3,442
    Shawn South
    Aug 16, 2004
  5. Replies:
    11
    Views:
    681
    Christos Georgiou
    May 2, 2006
Loading...

Share This Page