0

Why can't I access an instance variable directly in ruby without using an accessor method or instance_variable_get?

class Foo
   @my_var
end

Why shouldn't we be able to use Foo.@my_var in this example?

1
  • 1
    You are asking why Ruby wasn't designed to permit you to do that. That's not a suitable question for this forum, as it is open-ended and requires speculation. Commented Aug 4, 2016 at 6:25

2 Answers 2

2

The example provided by the OP is a class instance variable. These can only be accessed by class methods.

"regular" attribute accessors won't allow access from outside the class. Here are a couple of ways to create accessors that work:

class A
    @class_instance_var = "foo"

    class << self
        attr_accessor :class_instance_var
    end

end

puts A::class_instance_var  # Output: foo

OR

class A
    @class_instance_var = "foo"

    def self.class_instance_var
      @class_instance_var
    end
end

puts A::class_instance_var  # Output: foo

Class instance variables

Class instance variable names also begin with @. However, they are defined at class level, outside any methods. Class instance variables can only be accessed by class methods. They are shared amongst all instances of a class but not its subclasses. In other words, they are not inheritable. If the value of a class instance variable is changed in one instance of the class, all other instances are affected. Earlier we saw how all classes are instances of a built-in class called Class. That is what makes class instance variables possible.

class Vehicle
  @count = 0        # This is a class instance variable

  def initialize
    self.class.increment_count
    self.class.show_count
  end

  def self.increment_count    # This is a class method
    @count += 1
  end

  def self.show_count        # This is a class method
    puts @count
  end

end

class Car < Vehicle
  @count = 0
end

v1 = Vehicle.new    # Output: 1
v2 = Vehicle.new    # Output: 2
v3 = Vehicle.new    # Output: 3

car1 = Car.new        # Output: 1
car2 = Car.new        # Output: 2

v3 = Vehicle.new    # Output: 4

Let's review the example above. A class instance variable called @count is set in the Vehicle class, with an initial value of 0. Every time the Vehicle class is instantiated, the initialize method calls self.increment_count to increment the value of @count and self.show_count to return the new value. Then, we have the Car class, which is a subclass of Vehicle and inherits all of its methods. However, it does not inherit the @count class instance variable, as this type of variable is not inheritable. That's why the counter works within the Car class, but it has its own count.

Methods prefixed with self., such as self.increment_count and self.show_count, are class methods. That is the only kind of method capable of accessing class instance variables.

Sign up to request clarification or add additional context in comments.

Comments

1

That's just not how the language is built. Maybe look at openstruct

require 'ostruct'

obj = OpenStruct.new(my_var: 1)

obj.my_var
# => 1

By the way, you're method of setting up an instance variable is not correct. You should only be setting instance variables inside instance methods or initialize, otherwise use class variables or constants.

An example with constants:

class Foo
   MyVar = 1
end

Foo::MyVar
# => 1

You could also make Foo.new.@my_var work with method_missing:

class Foo
  def method_missing(m, *args, &block)  
    self.instance_variable_get(m)
  end
  def initialize
    @my_var = 1
  end
end

Foo.new.@my_var
# => 1

3 Comments

I'm not sure this answers the question. Why is it that it isn't accessible the way I set it up in the OP? It's a class instance variable.
Also why wouldn't the designers allow dot notation access (besides that's just how it is)?
@BrunoFacca this was a lonng time ago, but you are correct, my mistake . ... removed my comments saying it doesn't exist.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.