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.
Related
I am having trouble with some fundamental concepts in Ruby, specifically the interchangeability of a subclass for the superclass.
According to the Ruby documentation on classes, "Class" inherits from "Module".
https://ruby-doc.org/core-2.5.3/Class.html
class MyClassTest end
MyClassTest.is_a? Module # => true
However, when trying to use the module keyword to reopen a class defined with the keyword class, you get a TypeError that the class is not a module.
class MyClassTest end
module MyClassTest end # => TypeError: MyClassTest is not a module
This SO question has some excellent discussion surrounding subclasses vs subtypes, but I think it has lead me to more questions:
Why can't classes be used as modules?
Generally, since Ruby is dynamically typed, I am confused by the existence of TypeErrors.
Specifically, in this case, I am extra confused as to how Ruby inheritance can result in a TypeError where the subclass cannot be substituted for the superclass. In my mind, subclassing is equivalent to subtyping in Ruby since the subclass will inherit the interface (methods and public attributes) of the superclass.
My current guess is that TypeError's are raised by the core Ruby library when certain assertions fail, and these TypeErrors don't necessarily have anything to do with Ruby's dynamic typing system, which is to say that typing is not a first-class concept in Ruby. The linked SO question raises excellent points about the diamond problem with multiple class inheritance, so it makes sense that Ruby would prevent the interchangeable usage of modules and classes when using the module or class keyword. Still, it feels like there are inconsistencies in my understanding of Ruby.
How can a "Class" input result in a TypeError when a "Module" object is expected?
Basic assertions are
Class is a Class (Class.is_a?(Class) #=> true)
Class is a Module (Class.is_a?(Module) #=> true)
An instance of the class Class is a Class (Class.new.is_a?(Class) #=> true)
An instance of the class Class is a Module (Class.new.is_a?(Module) #=> true)
Module is a Class (Module.is_a?(Class) #=> true)
By virtue Module is a Module (Module.is_a?(Module) #=> true)
An instance of the class Module is a Module (Module.new.is_a?(Module) #=> true)
However An instance of the class Module is not a Class (Module.new.is_a?(Class) #=> false)
an instance of the class Class is an instance of Class but not and instance of the class Module (Class.new.instance_of?(Module) #=> false)
module is a declaration for an instance of the class Module just as class is a declaration for an instance of the class Class.
If this were a method it might look like
def module(name,&block)
raise TypeError if defined?(name) && !const_get(name).instance_of?(Module)
obj = defined?(name) ? const_get(name) : const_set(name, Module.new)
obj.instance_eval(&block)
end
TypeError exists to prevent ambiguity.
As in your case by using class MyClassTest you have created an instance of the class Class and that instance is called MyTestClass.
If you were also allowed to use module MyTestClass, in the same global context, then during usage I would be unaware if when calling MyClassTest I would be calling the Class or the Module.
The basic (very basic) difference is a Class can be instantiated (have instances) however a Module cannot.
For instance
Class.new.new #creates an instance of the anonymous class created by Class.new
Module.new.new # results in NoMethodError
I think the first point of confusion is the distinction between usage and definition.
The following code defines a class:
class C; end
If I see the above code, I expect to be able to instantiate C later:
C.new
However, imagine that C was already defined as a module:
# In one file:
module C; end
# Later in a different file:
class C; end # C is actually a module
C.new # fails
Ruby surfaces the problem (conflicting definitions of C) at the point where C is redefined as a class, rather than allowing the program to continue to where C is used.
The benefit of surfacing the problem earlier is generally the earlier an error is identified, the easier it is to find and fix its root cause (in this example, perhaps C is supposed to be a class after all, and thus the real issue is the module C definition).
Your second question is, I think, why a class cannot always be used as a module, for example why the following is prohibited:
class C; end
class A
include C
end
The answer, I think, is the programming language starts with concepts which are then implemented using various constructs. We could describe classes and modules as follows:
A class represents an object which has data and behavior (classic OOP definition).
A module is a collection of behavior.
The include keyword extends a class with a module's behavior. In principle it is possible to take just a class's methods and add them to another class. But this operation doesn't make sense because a class is an object and its behavior together. Taking just the behavior goes against the concept of the class.
There are other programming languages which take different positions on this issue. For example, in JavaScript any function can be taken out of any class and invoked with an instance of any other class. This can be convenient in some situations and difficult to debug in others.
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?
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 :-)
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.
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).
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
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.
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?
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 :-)
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.
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).
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
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.
I understand that singleton methods live in singleton classes (or eigenclasses). My first question is:
Why can't they live inside objects? I know that in ruby, an object can
only hold instance variables. But I cannot see why singleton methods
weren't designed to be in objects.
Next,
If objects can only contain instance variables, how come classes,
which are objects of Class, are able to store methods?
I am just confused at conceptual level. I have read many times that ruby object model is consistent.
Ad 1, they indeed do live inside an object. Singleton class, in fact, is just a mental construct. 'Singleton' here means, that, by definition, the class has only one instance - that object. So the identity of the object and the singleton class is intextricably the same.
Ad 2, the answer is, because Matz decided so. More precisely, not classes, but modules (Module class) store methods, and Class < Module.
It might be of interest to you, that a singleton class of an object is not instantiated by default. Until you try to access it, it simply does not exist. This is because if all the singleton classes were immediately instantiated, you would have an infinite chain of singleton classes:
o = Object.new
o.singleton_class
o.singleton_class.singleton_class
o.singleton_class.singleton_class.singleton_class
...
The goal of singleton pattern is to ensure, that only one object of a particular class will live within a system.
So the methods still live in a class, but you just can't create another instance of that class.
A class is an object, but because it serves as a template for other objects, its own instances, it keeps their instance methods inside its module. But if you treat a class as an ordinary object, for example call #object_id on it, it gives you all the behavior expected of normal objects.
Continuing from our discussion in comments: Strictly speaking, the ability to store methods (and constants) is a buit-in special ability of modules (Module class). Class class happens to be a subclass of Module class, which makes it inherit modules' ability to store methods, but you are free to create other objects (not just classes) with that ability:
class MyPetObjectThatCanStoreMethods < Module
def greet; puts "Bow, wow!" end
end
Fred = MyPetObjectThatCanStoreMethods.new
So, Fred is not exactly a module, but decsends from Module and has thus ability to store methods and constants:
module Fred # this is allowed!
LENGTH = 19
def rise; puts "I'm rising!" end
end
You can't do this with normal objects, only with module descendants!
Fred::LENGTH #=> 19
Fred.greet
#=> Bow, wow!
Fred.rise
#=> NoMethodError
That's because Fred stores #rise method, just like modules do, but unlike #greet method, #rise is not its instance method! To gain access to it, we will have to include Fred in a suitable class:
o = Object.new
o.rise
#=> NoMethodError
class << o # Including Fred in the metaclass of o
include Fred
end
o.rise
#=> I'm rising!
If objects can only contain instance variables, how come classes, which are objects of Class, are able to store methods?
class Foo
def suprim;end
end
Foo.instance_methods(true).grep(/^sup/)
#=> [:suprim]
I searched for Class's instance method superclass ,but didn't appear,as Foo is an instance of Class,so it should not store the
instance methods of Class. But yes,Foo returns only the methods of its instances to be used. Which is natural.Look below now:
Class.instance_methods(true).grep(/^sup/)
#=>[:superclass]
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?