ruby: class instance variables vs instance variabl

2019-09-15 03:06发布

问题:

my idea is to create a community wiki for people that come from a java background because reading a lot of explanations, I couldn't comprehend anything until I actually tried a couple of things and the pieces of the puzzle started to find their places. But I first need to make sure I'm getting it right. Coming from such background it was very confusing for me to find out that @variable may mean 2 very different things. Here is an example:

class Test
  @ins = "gah"
  def self.ins
    puts @ins
  end

  def initialize()
    @ins = "wtf?"
  end
  def ins2
    puts @ins
  end
end

As far as I understand, the first @ins is an instance variable of the object representing the class Test. The second @ins is an instance variable in an object of class Test.

Now things start to make some sense to me. Here a couple of examples:

[14] pry(main)> test.ins2
wtf?

We are calling a method of an object and it returns the object's instance variable.

[15] pry(main)> test.ins
NoMethodError: undefined method `ins' for #<Test:0x000000017d9348 @ins="wtf?">

We are trying to call a class method through an object, this method is of the class so we are getting NoMethodError

[16] pry(main)> Test.ins
gah

We are calling a class method so it properly sees the instance variable of the class object.

[17] pry(main)> Test.ins2
NoMethodError: undefined method `ins2' for Test:Class

We are calling an object method through the class which is incorrect so throwing NoMethodError.

All of the above was performed with ruby 2.0. So what am I asking?

  • Am I getting it right?
  • Am I getting the ruby terminology correct?
  • Any real usage of class instance variables that make sense in a properly designed app? Or are these simply the better @@class variables?

回答1:

it was very confusing for me to find out that @variable may mean 2 very different things.

No, it doesn't. Classes are objects just like any other object. They can have instance variables just like any other object. They can have instance methods just like any other object. In fact, unlike Java, which has three different kinds of "methods" (instance methods, static methods and constructors), in Ruby, there is exactly one kind of method: instance methods.

The beauty of having classes being objects is precisely that @variable always means exactly the same thing.

There is no such thing as a class instance variable: it's just a normal instance variable like any other. The object happens to be an instance of Class, but that doesn't change the nature of the instance variable. An instance variable of an object of class String is not a string instance variable, it's just an instance variable. Likewise, an instance variable of an object of class Class is just an instance variable.

There is no such thing as a class method: it's just a normal singleton method of an object which happens to be an instance of Class. (Acually, there's no such thing as a singleton method either: it's just a normal instance method of the object's singleton class.)

Note: Rubyists may use the term "class method" in casual conversation. But that doesn't mean that class methods actually exist, it only means that "instance method of the class object's singleton class" is a mouthful. The important thing is: because classes are objects, they work exactly like all other objects. They can have instance methods (defined in class Class or inherited from Module, Object, Kernel or BasicObject), they can have "singleton methods" (which really are instance methods of their respective singleton classes), they can have instance variables.

They can also have class variables (@@variables) … those are weird. Ignore them :-)



回答2:

  1. First, to understand instance variables, one need to know this - classes are objects.

    All classes are instances of Class(read the doc) which inherits from Object. That's why classes are objects.

  2. Then, every instance variables(ids marked with @, like @ins) are defined in self.

    When self is a class, they are instance variables of classes(class instance variables). When self is a object, they are instance variables of objects(instance variables).

  3. In different code scopes, the self represents different things.

    class Test
      # class scope, uncomment following line to see the value of self
      # p self
      @ins = "gah"
      def self.ins
        # class scope
        # p self
        puts @ins
      end
    
      def initialize()
        # object scope
        # p self
        @ins = "wtf?"
      end
      def ins2
        # object scope
        # p self
        puts @ins
      end
    end
    


回答3:

Everything looks right to me.

A class variable will be passed down through inheritance while an instance variable on a class will not. (src: Ruby class instance variable vs. class variable)

As far as design goes, I tend to prefer avoiding class variables altogether (I'd rather use a singleton), but if I had to choose one I would probably choose a class variable over a class instance variable to avoid confusion.