Having reference problems

Here is a code snippet:

class Foo
        @a
        @b
        @reference
               def initialize()
            @reference = [@a, @b]
        end

        attr_writer :a, :b, :reference
        attr_reader :a, :b, :reference
end

f = Foo.new()
f.reference[0] = 1
puts f.a #nil WTF!

What I am trying to do is refer to an instance variable both by its index in some array, and also directly.

Any help would be greatly apreciated.

SH

Hi --

Here is a code snippet:

class Foo
      @a
      @b
      @reference
            def initialize()
          @reference = [@a, @b]
      end

      attr_writer :a, :b, :reference
      attr_reader :a, :b, :reference
end

f = Foo.new()
f.reference[0] = 1
puts f.a #nil WTF!

What I am trying to do is refer to an instance variable both by its index in some array, and also directly.

Any help would be greatly apreciated.

OK, you need to clear some cobwebs :slight_smile:

First of all, this:

   @a

is just the value of @a. It doesn't do anything; it's essentially a
waste of electrons.

Second, there's a rule about instance variables that will help you
not only here but generally: *Whenever* you see an instance variable
(@a or whatever), that instance variable belongs to whatever object
is, at that moment, "self" (the current object).

If you peek inside a class definition, you'll find that the current
object is a class object:

   class Foo
     p self # Foo
   end

If you peek inside an instance method definition, you'll find that
self is the instance:

   class Foo
     def talk
       p self
     end
   end

   Foo.new.talk # #<Foo:0xbf510d18>

That means that you're dealing with two completely different scopes,
for instance variable (and most other) purposes:

   class Foo
     @a = 1 # this @a belongs to the Class object called Foo
     def initialize
       @a = 1 # *this* @a will belong to a newly-minted Foo instance
     end
   end

No two objects share instance variables -- even if one of the objects
happens to be an instance of the other object. Like about 3/4 of all
Ruby problems, this one comes down to: classes are objects too :slight_smile:

Third.... when you do this:

   foo.reference[0] = 1

you are *replacing* the first element of foo.reference with 1. At
this point, foo.reference will consist of:

   [1,nil] # the new 1 value, plus the default value of @b (nil)

Both @a and @b will be nil, because you have not assigned to either of
them.

David

···

On Wed, 26 Oct 2005, shalperin wrote:

--
David A. Black
dblack@wobblini.net

How about this?

class Referenceable
  def self.attr_reference(*attrs)
    @vars ||=
    @vars += attrs
    attr_accessor *attrs
    v = @vars
    define_method(:reference) do |i|
      self.send(v[i])
    end
  end
end

class Foo < Referenceable
  attr_reference :a,:b
end

f = Foo.new
f.a = 'this is a'
f.b = 'this is b'
f.reference(0)
=> 'this is a'
f.reference(1)
=> 'this is b'

regards,
Ed

···

On Wed, Oct 26, 2005 at 03:02:03AM +0900, shalperin wrote:

What I am trying to do is refer to an instance variable both by its
index in some array, and also directly.

Here is a code snippet:

class Foo
  @a
  @b
  @reference

This is not necessary and definitely does not do what you want it to do.
It actually accesses the @a, @b, and @reference variables in the class
Foo.

  def initialize()
    @reference = [@a, @b]
  end

  attr_writer :a, :b, :reference
  attr_reader :a, :b, :reference
end

f = Foo.new()
f.reference[0] = 1
puts f.a #nil WTF!

What I am trying to do is refer to an instance variable both by its
index in some array, and also directly.

Any help would be greatly apreciated.

Hmmm. Won't work, because variables in Ruby are just labels, not
shoeboxes as they are in other programming languages. What problem are
you adctually trying to solve and we can help you find a Ruby way of
doing it.

  class Foo
    def initialize
      @reference =
    end

    attr_accessor :a
    remove_method :a= ;
    def a=(_a)
      @reference[0] = @a = _a
    end

    attr_accessor :b
    remove_method :b= ;
    def b=(_b)
      @reference[1] = @b = _b
    end

    attr_reader :reference
  end

That's closer to what you want, but it's very static and fragile. I
recommned looking closer at what you're trying to solve and finding
another solution.

-austin

···

On 10/25/05, shalperin <shalperin@thebenefitbank.com> wrote:
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Having read your example more carefully, I think this does what you
really want. This works in reverse from my previous example, by
dynamically creating the accessors and storing the variables in an
Array:

class Referenceable
  def self.attr_reference(*attrs)
    @reference ||=
    attrs.each {|a|
      i = @reference.size
      define_method(a) do
        @reference[i]
      end
      define_method((a.to_s + "=").intern) do |val|
        @reference[i] = val
      end
      @reference << nil
    }
    def self.refsize
      @reference.size
    end
  end
  
  attr_reader :reference
  def initialize
    @reference = Array.new(self.class.refsize)
  end
end

class Foo < Referenceable
  attr_reference :a,:b
end

f = Foo.new
f.a = 1
f.b = 2
f.reference
=> [1,2]
f.reference[0] = 'test'
f.a
=> 'test'

regards,
Ed

···

On Wed, Oct 26, 2005 at 03:02:03AM +0900, shalperin wrote:

What I am trying to do is refer to an instance variable both by its
index in some array, and also directly.

Hi,

try this:

class Foo
  attr_accessor :reference
  def initialize()
    @reference = []
  end
  def a=(value)
    @reference[0] = value
  end
  def a
    @reference[0]
  end
  def b=(value)
    @reference[1] = value
  end
  def b
    @reference[1]
  end
end

foo = Foo.new
foo.a = 42
p foo.reference[0]
foo.reference[1] = 3
p foo.b
foo.reference = ["Hello", "world"]
p foo.a

__END__

Output is:

42
3
"Hello"

You might also want to revise classes, attributes, attr_accessor
(along with attr_reader and attr_writer) and initialize.

Regards,

Sean