3

In PHP I write:

Class Test{
  public $a=100;
}

$a=new Test();
echo $a->a; //prints 100

It prints 100, but In ruby when I write:

class Test
  @a=100
  attr_accessor :a
end

a=Test.new
puts a.a #=> prints nil

a is nil and it prints nil. Why?

emj
  • 55
  • 6

4 Answers4

3

You're mixing things a bit.

What you've defined with @a = 100 is a class instance variable.

What you're going to have access to with attr_accessor :a is an instance variable @a.

Example of instance variable usage:

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

instance = A.new(2)
#=> 2
instance.instance_variables
#=> [:@a]
instance.a
#=> 2

Example of class instance variable usage:

class A
  @a = 1
  class << self
    attr_accessor :a
  end
end

A.a
#=> nil
A.a = 2
#=> 2
A.a
#=> 2
instance = A.new
instance.class.a # access instance's class instance variable
#=> 2
Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
  • Thank you for your explanation. So, can I say that `a` in inherited classes will be accessible with `100` value? – emj Sep 13 '16 at 15:11
  • 2
    `cattr_accessor` is part of rails and inappropriate for this question (no `rails` tag) – sokkyoku Sep 13 '16 at 15:12
  • @sokkyoku thx, edited – Andrey Deineko Sep 13 '16 at 15:15
  • 1
    @emj, right. You can test it with `class B < A; end` and `B.a` – Andrey Deineko Sep 13 '16 at 15:16
  • You should clarify, "Class instances DO NOT have access to their class' instance variables." If `@a` is a class instance variable with value "dog" and `@b` is an instance variable, `@b.class.a #=> "dog"` if `@a` has a read accessor, else `@b.class.instance_variable_get("@a") #=> "dog"` – Cary Swoveland Sep 13 '16 at 16:56
  • @CarySwoveland I was not around my laptop since answered and was sure someone would stumble upon this sentence of mine :) Really there's nothing "inaccessible" in Ruby, but I'll update the answer once I am near laptop – Andrey Deineko Sep 13 '16 at 16:59
2

Instances variables belong to objects (aka instances), that's why they are called "instance variables" after all.

There are two objects here: Test, which is an instance of Class, and a, which is an instance of Test. Both are objects just like any other object. Both can have instance variables just like any other object.

Both have an instance variable called @a. Foo's @a has been initialized to 100. a's @a hasn't been initialized at all, and unitialized instance variables evaluate to nil.

So, your problem is that you are confusing which instance you are looking at. Instance variables are always looked up in self, and inside a class definition body, self is the class being defined.

This may sound pedantic, but I find that understanding that Ruby is actually much simpler than people sometimes want you to believe, will ultimately help you.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
1

Try this instead:

class Test
  attr_accessor :a

  def initialize
    @a = 100
  end
end

a = Test.new
puts a.a
seph
  • 6,066
  • 3
  • 21
  • 19
1

The reason this is happening is that this line:

@a = 100

is assigning to an instance variable but not the one you think. It is being assigned to Test.a, (Test being an instance of Class) rather than to an instance variable a belonging to each instance of Test

In turn, this line:

attr_accessor :a

is declaring an accessor to an instance variable called a (accessible through any instance of Test)

Thus you should either have

class Test
    @a = 100
    class << self
        attr_accessor :a
    end
end
puts Test.a #=> will print 100

or

class Test
    def initialize
        @a = 100
    end
    attr_accessor :a
end
a = Test.new
puts a.a #=> will print 100

It depends if you just want a class constant or if you want an attribute with a default value on each instance. The latter is a direct translation of your PHP code.

sokkyoku
  • 2,161
  • 1
  • 20
  • 22
  • 1
    It would be more precise (and ultimately more helpful) to say that that line *is* assigning an instance variable. After, all, it is an assignment (`=`), and it is an instance variable (`@`). It's just that the instance isn't the one the OP thinks it is. It *is* an instance variable, but for the *wrong* instance. – Jörg W Mittag Sep 13 '16 at 16:06
  • Good point, amended my answer – sokkyoku Sep 13 '16 at 16:12