Class-instance variables access

Hi,

I try to understand the difference between ‘class variables’ and ‘class
instance variables’, following a post by Guy Decoux a few days ago.

class A
@x = 12 # (class instance) variable

def A.test
puts @x
end

def instance_method
puts @@x # does not work, I’m sad :wink:
end
end

A.new.instance_method
=> NameError: uninitialized class variable @@x in A

I understand that @@x refers only to a (non existant) class variable of A. I
don’t catch why there is a distinction between a class instance variable and
a class variable: the two are “stored” in the unique object representing the
class A, no ?

Is there a way to access the x variable from an instance of A ?

Francois

I try to understand the difference between ‘class variables’ and ‘class
instance variables’, following a post by Guy Decoux a few days ago.

If you’ve ever worked with C or Java, a class variable is like a variable
declared ‘static’

class A
def intialize(y)
@x = y
@@x = y
end
def test
puts “@x: #{@x}”
puts “@@x: #{@@x}”
end
end

foo = A.new(“foo”)
bar = A.new(“bar”)

foo.test
bar.test

  • You get:
    @x: foo
    @@x: bar
    @x: bar
    @@x: bar

@x is an instance variable that each instance stores it’s own version of
@@x is a class variable that is stored in the class definition

@x can be different from instance to instance, @@x is the same for all
instances.

···

Greg Millam
walker at deafcode.com

a class variable is unique for a class object
a instance variable is unique for an instance of a class

class A
@@uniq_for_class ## all instance see one variable
@one_per_instance ## each instance hold one variable
end

hope this help!

(in C++, this is same difference between static methods and other)

···

On Fri, 06 Dec 2002 21:54:59 +0900, Francois GORET wrote:

Hi,

I try to understand the difference between ‘class variables’ and ‘class
instance variables’, following a post by Guy Decoux a few days ago.

class A
@x = 12 # (class instance) variable

def A.test
puts @x
end

def instance_method
puts @@x # does not work, I’m sad :wink:
end
end

A.new.instance_method
=> NameError: uninitialized class variable @@x in A

I understand that @@x refers only to a (non existant) class variable of A. I
don’t catch why there is a distinction between a class instance variable and
a class variable: the two are “stored” in the unique object representing the
class A, no ?

Is there a way to access the x variable from an instance of A ?

Francois

I understand that @@x refers only to a (non existant) class variable of A. I
don't catch why there is a distinction between a class instance variable and
a class variable: the two are "stored" in the unique object representing the
class A, no ?

Well, what you must understand is just this

pigeon% ruby -e 'p Array.ancestors'
[Array, Enumerable, Object, Kernel]
pigeon%

See Object in the inheritence.

in ruby a class is an object like any other object.

Now when you write this

   class A
      def initialize
         @a = 12
      end
   end

   a = A.new

You have created an object of class A, and you have defined an instance
variable for this object. Only this object can access its instance
variable and if you want to make it "public" you define an accessor like
this

   class A
      attr_accessor :a
      def initialize
         @a = 12
      end
   end

   a = A.new
   a.a = 24

This work for *all* objects, and because it work for all objects it work
also for a class (a class is an object). this mean that you can write

   class A
      @b = 12
   end

and you have defined an instance variable for the object A, and only A can
access it. Like previously, if you want to make it "public" you must
create an accessor, something like this

   class A
      class << self
         attr_accessor :b # attr_accessor is for the class, not the
                           # instance, this is why I've used class << self
      end
      @b = 12
   end

   A.b = 24

and now you can access the instance variable of A and you can write

   class A
      class << self
         attr_accessor :b
      end
      @b = 24

      attr_accessor :a
      def initialize
         @a = 12
      end

      def show
         puts "class instance variable #{self.class.b}"
         puts "instance variable #{self.a}"
      end
   end

   a = A.new
   a.show

Guy Decoux

Hi Greg,

Thanks for your help. In fact the question was a little bit different: you can
define IN A CLASS what’s Guy called “class instance variables”. I was stunned
by this a few days ago, as I was assuming too that there are only “class
variables” and “instance variables”, the ones you described.

Class instance variables seems to be a third kind of animal: variables stored
in the class (not in it’s instances), and who does support the following
construct:

class B
def B.test
@x
end
end

class A < B
@x = 12 # not @@x = 12
end

A.test
=> 12

If you do the same with @@x, it doesn’t work as the class method B.test will
try to access the non-existant @@x IN B, not in A.

So I’m really puzzled by these class instance variables… and I didn’t find a
way to access their values from an instance.

Thanks again for your help,

Francois

···

On Friday 06 December 2002 20:08, Greg Millam wrote:

I try to understand the difference between ‘class variables’ and ‘class
instance variables’, following a post by Guy Decoux a few days ago.

If you’ve ever worked with C or Java, a class variable is like a variable
declared ‘static’

class A
def intialize(y)
@x = y
@@x = y
end
def test
puts “@x: #{@x}”
puts “@@x: #{@@x}”
end
end

foo = A.new(“foo”)
bar = A.new(“bar”)

foo.test
bar.test

  • You get:
    @x: foo
    @@x: bar
    @x: bar
    @@x: bar

@x is an instance variable that each instance stores it’s own version of
@@x is a class variable that is stored in the class definition

@x can be different from instance to instance, @@x is the same for all
instances.

Well, what you must understand is just this

I've forgotten to give the complete example :frowning:

pigeon% ruby -e 'p Array.ancestors'
[Array, Enumerable, Object, Kernel]
pigeon%

pigeon% ruby -e 'p Class.ancestors'
[Class, Module, Object, Kernel]
pigeon%

  See Object in the 2 inheritence.

Guy Decoux

Hi –

a class variable is unique for a class object
a instance variable is unique for an instance of a class

class A
@@uniq_for_class ## all instance see one variable
@one_per_instance ## each instance hold one variable
end

Not quite. In your example, @one_per_instance is not visible to
instances of class A. It’s an instance variable of class A.

irb(main):001:0> class A
irb(main):002:1> @var = “hello”
irb(main):003:1> end
“hello”
irb(main):004:0> A.instance_variables
[“@var”]
irb(main):005:0> A.new.instance_variables

You could make @var visible, through an accessor, but by default it’s
visible only to the object whose instance variable it is – namely,
the object A (which is a Class object).

(See also Guy D.'s further explication.)

David

···

On Fri, 6 Dec 2002, Ludo wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

Hi Greg,

Thanks for your help. In fact the question was a little bit different: you can
define IN A CLASS what’s Guy called “class instance variables”. I was stunned
by this a few days ago, as I was assuming too that there are only “class
variables” and “instance variables”, the ones you described.

Class instance variables seems to be a third kind of animal:
variables stored in the class (not in it’s instances), and who does
support the following construct:

[This may overlap with other stuff that’s been posted, but, well, here
it is :-]

The term “class instance variable” is useful but potentially
misleading, because it makes them sound like a special case. In fact,
they are just instance variables, belonging to a particular object.
There’s no third animal involved :slight_smile:

Let’s say you did this:

s = String.new(“hello”)
s.instance_eval { @var = 100 }

Now the object s has an instance variable. That variable can only be
seen when self == s, which we can achieve with instance_eval:

s.instance_eval { puts @var } # 100

@var is not available to any string, just to s:

“some other string”.instance_eval { puts @var } # nil

The exact same thing happens with classes. You can perhaps see this
more clearly if we use the same syntax:

c = Class.new
c.instance_eval { @var = 100 }
c.instance_eval { puts @var }

We’ve defined an instance variable on an object. It just happens to
be a Class object. We can do the same test, to show that @var is not
an instance variable of any Class object, just this one:

Array.instance_eval { puts @var } # nil

And there’s a further test we can do, if we want – namely (since this
is a Class object) to examine an instance of the class:

c.new.instance_eval { puts @var } # nil

Our instance of c (c.new) is a different object from c itself.
Therefore, it does not share c’s instance variables. No two objects
share instance variables.

And you can also see that though c happens to be a Class object,
whereas our first example, s, was a String object, the behavior is
exactly the same.

The only difference is in writing style and syntax, because (in spite
of being “just objects”) classes do get some special syntax. Class
definitions are usually written like this:

class Thing

end

But inside that block (at the top level, outside of any 'def’s),
‘self’ is set to Thing. So it’s a lot like writing:

Thing = Class.new
Thing.instance_eval { … }

So there’s certainly special syntax associated with class definitions.
But it’s just a front-end to getting into the ‘self’ scope of an
object – an object of type Class – which is really much the same as
getting into the ‘self’ scope of any other object (with
instance_eval).

David

···

On Fri, 6 Dec 2002, Francois Goret wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

The term "class instance variable" is useful but potentially
misleading,

Just wait to have "class local variable" :-)))

Guy Decoux

The term “class instance variable” is useful but potentially
misleading,

Just wait to have “class local variable” :-)))

NOOOOOOOO!!! PLEEEEEEAAASE NOOOOOOOOO!!! I can’t take any more of this
weird Ruby stuff! I’ve been coding J@#% for 10 hours straight!

<Ahhhh! That feels better>

Gavin

(Actually, David, if you want to blabber on about class local variables, I’m
all ears :wink:

···

From: “ts” decoux@moulon.inra.fr

(Actually, David, if you want to blabber on about class local variables, I'm
all ears :wink:

Well, I'll try to explain where is the problem with instance
variables. Imagine that you have

   class A
      def initialize
         @a = 12
      end

      def show
         puts @a
      end
   end

   class B < A
      def show
         puts @a
         super
      end
   end

   b = B.new
   b.show

What you must see in my example is that the instance variable is
associated with self (i.e. the object) and ruby will access the same
variable in A#show and B#show. This is just what you want and it work
fine, but now imagine that the class A was written by someone and the
class B by written by another person, and these 2 persons write

   class A
      def initialize
         @a = 12
      end

      def show
         puts @a
      end
   end

   class B < A
      def initialize
         @a = 24
      end

      def display
         puts @a
      end
   end

   b = B.new
   b.display
   b.show

The person which has written B has defined an instance variable `@a'
without knowing that this instance variable was also defined by the
person which has written A, and ruby just display the same value.

It exist some case where you want that an instance variable can be
accessed and modified only within a class. This mean that the instance
variable which is associated with an object will be "class local"

In this case, the proposition was to write

   class A
      def initialize(value)
         @_a = value
      end

      def show
         puts @_a
      end
   end

   class B < A
      def initialize(value)
         @_a = value
         super(2 * value)
      end

      def display
         puts @_a
      end
   end

   b = B.new(12)
   b.display # ===> 12
   b.show # ===> 24

i.e. you have different value of @_a which will depend on the class.

You have "class local variable" :slight_smile:

Guy Decoux