Class variables inheritance in Ruby - ruby

I understand that this question has been raised many times already. But I can't find the complete guide about all those kinds of variables. I've found a couple of articles that compare class variables vs class instance variables, but what about instance variables?
So, what is the difference between: instance variables, class variables and class instance variables? What kind of variables are inheritable and what are not?

An instance variable is, well, a variable that belongs to one specific object (aka instance). Inheritance is irrelevant in this case, since objects can't inherit from anything, only classes can.
Class instance variables don't exist. Classes are objects just like any other, so they can have instance variables just like any other object. When a class has an instance variable, this is sometimes called a class instance variable, but it's just an instance variable. So, again, it can't be inherited.
Class variables are strange beasts. They are shared among
the class itself
all instances of the class
all subclasses of the class
all instances of all subclasses of the class
all subclasses of all subclasses of the class
all instances of all subclasses of all subclasses of the class
… and so on …
They are really more like global variables, considering how widely they are shared.
You can call this sharing inheritance, but I don't think that's a useful term. There is no polymorphic dispatch, no message sending, no overriding.
In Ruby, the term inheritance really only makes sense with methods, not with variables.

Instance Variables are variables which are the ones whose data varies with each instance of the object.
Class variables are those which are shared across all instances of a class. Actually every instance points to the same value and change is seen across all the class instances.

Related

Ruby class method and instance method

I am trying to call a method on File. I read the documentation of File and I see the class method ::basename. I tried the following:
x = File.new("name_of_file.ext")
x::basename("name_of_file.ext")
Why can't I access the class method ::basename in this way?
There is no such thing as a class method in Ruby. Classes are objects like any other object in Ruby. Like any other object in Ruby, they are instances of a class, namely the class Class.
So, just like any other object has methods that are defined in its class, classes also have methods that are defined in its class.
That's one half of the story. "Class methods" like ::new are typically like this. Class#new is an instance method of class Class, and since File is an instance of Class, you can call File.new.
The other half of the story is that every object in Ruby has a singleton class, a class that this object is the only instance of. Since this class has only one instance, any instance methods defined in this singleton class can only be called on that one single object. Since classes are objects like any other object, they have a singleton class like any other object, and methods can be defined there. For example, File::basename is defined as an instance method of the singleton class of File.
The reason why you cannot call x.basename is really simple: File and x are completely different objects which are instances of completely different classes, so why would you expect to be able to call the same method on both? Well, you wouldn't! Different objects that are instances of different classes usually have different methods.

difference between class method , instance method , instance variable , class variable?

I recently started learning ruby. I am confused between class methods, instance methods, instance variables, and class variables. I googled a lot, but I didn't get any clarification on those. Any help along with examples would be appreciated.
First take a look at this diagram:
You can rightly say that “obj has a method called my_method( ),” meaning that you’re able to call obj.my_method(). By contrast, you shouldn’t say that “MyClass has a method named my_method().” That would be confusing, because it would imply that you’re able to call MyClass.my_method() as if it were a class method.
To remove the ambiguity, you should say that my_method() is an instance method (not just “a method”) of MyClass, meaning that it’s defined in MyClass, and you actually need an instance of MyClass to call it. It’s the same method, but when you talk about the class, you call it an instance method, and when you talk about the object, you simply call it a method. Remember this distinction, and you won’t get confused when writing introspective code like this:
String.instance_methods == "abc".methods # => true String.methods == "abc".methods # => false
an object’s instance variables live in the object itself, and an object’s methods live in the object’s class. That’s why objects of the same class share methods but don’t share instance variables.
I am confused between class methods, instance methods,
There is no such thing as a "class method" in Ruby. There is exactly one kind of methods: instance methods.
Rubyists will sometimes talk about "class methods", but that is just a convenient name we use to refer to "instance methods of the singleton class of an instance of the Class class". That's quite a mouthful, and so we will abbreviate it to "class methods", but we know full well that class methods don't exist in the Ruby language.
instance variables, and class variables.
Really, the distinction is pretty much what it says on the tin: instance variables belong to objects (aka instances), whereas class variables belong to classes. Actually, class variables have pretty broad scope: a class variable is visible inside the class it is defined in, all of its instances, all of its subclasses, all instances of its subclasses, all of its subclasses' subclasses, all instances of all of its subclasses' subclasses and so on and so forth. Basically, class variables are visible through the entire class sub-hierarchy and all direct and indirect instances.
Note that classes are objects like any other, they are instances, too (of the Class class). Which means they can have instance variables as well, just like all other objects. 99% of the time, when you think you want a class variable, you actually want an instance variable of the class.

Understanding Ruby Classes and Modules

I have a number of questions regarding ruby classes and modules. I have written a number of test files to kind of explore them further that are too long to post here (https://github.com/Senjai/Learning-Ruby/blob/master/class_test.rb and https://github.com/Senjai/Learning-Ruby/blob/master/mixin-instance-var-conflict.rb)
First three questions are about variables.
So far that I understand it, instance variables are prefixed with #, and are unique to each instance of the class. They can only be accessed with accessor methods (like attr_accessor)
Second, class variables, they're prefixed by ##.
How come class variables can't be used with attr_accessor/reader?
What's the difference between class.class_variable and instance.class_variable? If an instance modifies a class variable from within the class (e.g in an instance method) does that affect the static variable in the class definition?
Thirdly,
Why do instance/class variables need to be prefixed with #? What happens when they aren't prefixed at all? Like in the example below:
module Test
State = {}
def state=(value)
State[object_id] = value
end
def state
State[object_id]
end
end
For class methods, I understand that instance methods are defined as normal functions, and class methods have to be prefixed with self. Why can't you use class methods in an instantiated object? Why does self make it so special?
Lastly, for the scope resolution operator, I've only found that it works for constants and class methods, what's the point of having a scope resolution operator in the first place if they can be accessed in dot notation?

Ruby: ##var or #var in Ruby modules?

Is there a reason to not use #var or ##var in a Ruby module that is not destined to be used as a mixin in a class? I've experimented and both variables results in the same behavior (simple module with basically a getter and setter for an #var or ##var). I havent found an example or explanation that says a module can be used with some mutable state. It almost seems to serve as a singleton in java.
I found a piece of code that used ##vars all over and it was never include/extend -ed in any other class so basically the developer was using the module to hold some state that may get updated but want all consumers of the module to see the same state at any given time and I suppose I could see some cases where this would be valuable, but since I've never seen any documented cases of this, I found it odd.
Regardless, is there any difference in an instance #var vs a 'class' ##var in the context of a module?
EDIT:
So I experimented a bit more. So my above question was assuming no usage of mixins. This basically says that there is a class variable for all.....one instance of the module (again somewhat like a singleton) or you have an instance variable that is shared among all...one instance of the Module so using either for state results in the same behavior. However, I made a instance method that's basically an instance getter to go along with my module method getter and did a mixin a class. In the case of the ##var, the single module instance and all classes share the value it is set to. With #var, the single 'module instance' had it's own value and then each class instance that sets #var for the mixin instance method had it's own #var.
I suppose this makes sense.
I don't think there is any difference if the module is not included in a class. The differences between an instance variable of a class and a class variables are:
Class variables are shared among the subclass. If A is a subclass of B, then ##foo of A is the same object as ##foo of B, but #foo of A is different from #foo of B.
Class variables are shared among the class and all of its instances. If a, b are instances of A, then ##foo of A is the same object as ##foo of a and ##foo of b, but #foo of A, #foo of a, and #foo of b are diffferent.
Both of these are not relevant for modules that are not included in a class.
But since the use of a class variable may imply that there is such sharing between subclass and/or between a class and/or its instances, for clarity, it may be better to use an instance variable of a class rather than a class variable.

Using Instance Variables in Class Methods - Ruby

I have a class something like below, and I used instance variables (array) to avoid using lots of method parameters.
It works as I expected but is that a good practice?
Actually I wouldn't expect that worked, but I guess class methods are not working as static methods in other languages.
class DummyClass
def self.dummy_method1
#arr = []
# Play with that array
end
def self.dummy_method2
# use #arr for something else
end
end
The reason instance variables work on classes in Ruby is that Ruby classes are instances themselves (instances of class Class). Try it for yourself by inspecting DummyClass.class. There are no "static methods" in the C# sense in Ruby because every method is defined on (or inherited into) some instance and invoked on some instance. Accordingly, they can access whatever instance variables happen to be available on the callee.
Since DummyClass is an instance, it can have its own instance variables just fine. You can even access those instance variables so long as you have a reference to the class (which should be always because class names are constants). At any point, you would be able to call ::DummyClass.instance_variable_get(:#arr) and get the current value of that instance variable.
As for whether it's a good thing to do, it depends on the methods.
If #arr is logically the "state" of the instance/class DummyClass, then store it in instance variable. If #arr is only being used in dummy_method2 as an operational shortcut, then pass it as an argument. To give an example where the instance variable approach is used, consider ActiveRecord in Rails. It allows you to do this:
u = User.new
u.name = "foobar"
u.save
Here, the name that has been assigned to the user is data that is legitimately on the user. If, before the #save call, one were to ask "what is the name of the user at this point", you would answer "foobar". If you dig far enough into the internals (you'll dig very far and into a lot of metaprogramming, you'll find that they use instance variables for exactly this).
The example I've used contains two separate public invocations. To see a case where instance variables are still used despite only one call being made, look at the ActiveRecord implementation of #update_attributes. The method body is simply load(attributes, false) && save. Why does #save not get passed any arguments (like the new name) even though it is going to be in the body of save where something like UPDATE users SET name='foobar' WHERE id=1;? It's because stuff like the name is information that belongs on the instance.
Conversely, we can look at a case where instance variables would make no sense to use. Look at the implementation of #link_to_if, a method that accepts a boolean-ish argument (usually an expression in the source code) alongside arguments that are ordinarily accepted by #link_to such as the URL to link to. When the boolean condition is truthy, it needs to pass the rest of the arguments to #link_to and invoke it. It wouldn't make much sense to assign instance variables here because you would not say that the invoking context here (the renderer) contains that information in the instance. The renderer itself does not have a "URL to link to", and consequently, it should not be buried in an instance variable.
Those are class instance variables and are a perfectly legitimate things in ruby: classes are objects too (instances of Class) and so have instance variables.
One thing to look out for is that each subclass will have its own set of class instance variables (after all these are different objects): If you subclassed DummyClass, class methods on the subclass would not be able to see #arr.
Class variables (##foo) are of course the other way round: the entire class hierarchy shares the same class variables.

Resources