ruby: class instance variables vs instance variables
Asked Answered
P

3

4

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?
Prudence answered 29/7, 2014 at 21:23 Comment(8)
wt*? :D Funny post. +1International
you can call it class method but technically it is not. It's a method for the singleton class watch this youtube.com/watch?v=X2sgQ38UDVYProgress
@SamD, thanks for the video, I'll definitely watch it. But I can't understand why should I call it a "singleton class". That would imply there are other types of classes. Isn't it better to call it a method of the class object? So it will be "class object" vs "class instance" where the former is the object representing the class and the latter - an object of that class?Prudence
Singleton class is an anonymous class that is hidden in the background when you define self.method the anonymous class(singleton) gets initialized and the method added to it. any self.method after that is added to the singletonProgress
@SamD, excuse me, I can't comprehend that. Perhaps it's in the video I'll watch sometime later. But what is a class then when everything is an object? In any case it becomes offtopic. What I was asking is why call it a "singleton class" instead of a "class" when all classes are like what you're describing above.Prudence
its a class like any other but hidden. you can think of it as a class that holds all the 'class' methods . watch the movie and you'll get it its easy.Progress
@SamD, watched the video. Nice info so thanks a lot for that. What I'm understanding though is that the said singleton/virtual/shadow/whatever classes are in fact lacking an official name and are an implementation detail that is hidden from the programmer as much as possible. As much as the guy tries to explain how classes are implemented, they are still classes because that's the the concept the language seems to promote. That's why I think calling it a class method is ok. Meaning of class is useful detail but nothing stops ruby to change class implementation in next version. Unlikely, yes!Prudence
Like I said, you can call it a class method, but if we want to be precise, those methods belong to another class(singleton) that is initialized after making the first self.method.Progress
I
11

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 :-)

Impercipient answered 29/7, 2014 at 21:39 Comment(1)
Well sorry but in that logic we can say that nothing is different because everything is actually bits :) In a typical OO design an instance variable and a class instance variable (I think we agree on the definitions) are different things semantically to the program. And we need some terms when we are speaking to easily understand each other. I think it is a deficiency in ruby docs that these concepts are not clearly described (at least I could not find a clear explanation). +1 for providing interesting details.Prudence
C
6
  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
    
Cartouche answered 30/7, 2014 at 1:41 Comment(0)
A
0

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.

Autostability answered 29/7, 2014 at 21:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.