How does inheritance work when it comes to class methods in Ruby?
There is only one copy of the method.
Explanation:
1. Singleton classes are instances
SubClass
and SuperClass
are both instances of Class
. If you inspect the singleton class in IRB, you'll see something like:
> SuperClass.singleton_class
=> #<Class:SuperClass>
> SubClass.singleton_class
=> #<Class:SubClass>
The SuperClass.singleton_class
is an ancestor of SubClass.singleton_class
just the same way that SuperClass
is an ancestor of SubClass
. Said another way: classes are also instances (of Class), and work by the same rules.
2. instance_methods
takes an optional argument
These rules say that SubClass.singleton_class.instance_methods
will return every instance method available, no matter which ancestor defines it. If you would like to only see instance methods defined on SubClass.singleton_class
, you need to invoke SubClass.singleton_class.instance_methods(false)
.
http://ruby-doc.org/core-2.4.1/Module.html#method-i-instance_methods
How does Inheritance work in Ruby?
Eigenclass is a sneaky hidden one. You have successfully revealed it by opening class. But it does not exist in the ancestors of normal class. And since it is hidden, you cannot see it by sending ancestors
method to a eigenclass itself. The inheritance tree is like the following:
B ---S--> Dave ---S---> Object ---S---> BasicObject
| | | |
E E E E
| | | |
#B --S--> #Dave ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject
S
stands for superclass, while E
for eigenclass.
How does class method look-up work during inheritance in ruby?
OK, since this question was upvoted, I’ll leave the correct answer here.
Child.hello
is defined because Child
’s eigenclass is derived from Parent
’s eigenclass:
▶ Child.singleton_class.superclass
#⇒ #<Class:Parent>
The whole ancestor chain of this eigenclass would be:
▶ Child.singleton_class.ancestors
#⇒ [#<Class:Child>, #<Class:Parent>,
# #<Class:Object>, #<Class:BasicObject>,
# Class, Module, Object, Kernel, BasicObject]
First four ancestors are eigenclasses of the respective classes in Child.ancestors
chain. That is how eigenclasses are built/derived in ruby, making calls like Child.hello
available.
And, while :hello
method is not shown directly by Child.singleton_class.instance_methods(false)
, since it’s defined not on Child
’s eigenclass, it’s still there, thanks to Parent
’s eigenclass:
▶ Child.singleton_class.instance_methods.detect &:hello.method(:==)
#⇒ :hello
Understanding Ruby Inheritance
Class methods may be inherited and overridden just as instance methods can be. If your parent class defines a class method, the subclass inherits that method. That is, if your subclass does not define it's own class method, then it inherits from it's superclass.
As a recommendation: when invoking a class method with an explicit receiver, you should avoid relying on inheritance. Always invoke the class method through the class that defines it. Otherwise, it would be very difficult for someone who relies on your code to find the parent class which defines the class method.
Referring back to your original assumption: the invocation of a class method from a subclass it's possible because the class methods are instance methods of the eigenclass
.
class C
# instance methods goes here
class << self # open the eigenclass
# class methods go here as instance methods of the eigenclass
end
end
In general, it's clearer to define class methods as individual singleton methods without explicitly opening the eigenclass.
For a clear explanation read The Ruby Programming Language by David Flanagan and Yukihiro Matsumoto
Ruby Inheritance and overwriting class method
I think this should clarify:
class Parent
def self.inherited(child)
puts "Inherited"
end
end
class Child < Parent
puts "Starting to define methods"
def self.stuff; end
end
Output makes it clear that .inherited
gets called the moment you open the new class, not when you close it. Thus, as you guessed, Child.custom_class_method
does not exist at the point when you are trying to call it - all .inherited
sees is a blank slate.
(As to how to get around it... I can't say without more insight into what you are trying to do, unfortunately.)
Inheriting from class Module
Module
is indeed a Ruby class. An instance of the class Module
is a Ruby module. To illustrate, these two ways of defining a module are equivalent:
module MyModule
# ...
end
# is equivalent to
MyModule = Module.new do
# ...
end
If an instance of Module
is a Ruby module, that means that an instance of any subclass of Module
is also a Ruby module, including Shrine::Attachment
. This makes sense, because we know that we can include
only modules, so an instance of Shrine::Attachment
has to be a module.
Because of Shrine's plugin system design, this:
class Attachment < Module
@shrine_class = ::Shrine
end
isn't the whole implementation of Shrine::Attachment
; the actual implementation is defined in the Shrine::Plugins::Base::AttachmentMethods
module, which gets included into Shrine::Attachment
.
If we look at the implementation of Shrine::Attachment.new
, we can see that it dynamically defines methods on itself based on the given attribute name. For example, Shrine::Attachment.new(:image)
will generate a module with the following methods defined: #image_attacher
, #image=
, #image
, and #image_url
. These methods will then get added to the model that includes that Shrine::Attachment
instance.
Why didn't I just have a method that creates a new module via Module.new
(like Refile does), instead of creating a whole subclass of Module
? Well, two main reasons:
First, this gives better introspection, because instead of seeing #<Module:0x007f8183d27ab0>
in your model's ancestors list, you now see an actual Shrine::Attachment
instance that points to its definition. You could still manually override #to_s
and #inspect
, but this is better.
Second, since Shrine::Attachment
is now a class, other Shrine plugins can extend it with more behaviour. So remote_url plugin adds the #<attachment>_remote_url
accessor, data_uri plugin adds the #<attachment>_data_uri
accessor etc.
Inheritance and instance variable in Ruby
B
inherits initialize
from A
.
At object creation, initialize
is invoked. So you get @x
set to 2
even for objects of class B
.
I think, the sentences you are quoting refer to this scenario:
class A
def initialize
@x = 42
end
end
class B < A
def initialize
@x = 23
end
end
h = B.new
Now, h
has just one instance variable @x
with value 23
. It is not like there is one @x
from B
and one from A
. You can see this here:
class A
def initialize
@x = 42
end
def set_x_from_a
@x = 12
end
def print_x_from_a
puts @x
end
end
class B < A
def initialize
@x = 23
end
def set_x_from_b
@x = 9
end
def print_x_from_b
puts @x
end
end
h = B.new
h.print_x_from_a # => 23
h.print_x_from_b # => 23
h.set_x_from_a
h.print_x_from_b # => 12
h.set_x_from_b
h.print_x_from_a # => 9
Why do we use super in ruby when I can inherit without its use?
Using super
lets a class override a method that it inherits from its parent and customize it.
For instance, in your example, Dog
and Cat
inherit #initialize
from Animal
- but what if we wanted some special logic for Dog
?
class Dog < Animal
def initialize(type, breed, age)
raise "Sorry, dogs don't live that long!" if age > 100
# Everything looks good - let Animal#initialize run now
super
end
end
This lets Dog
customize what its initialize method does, but still call through to the original inherited method.
Related Topics
Encryption-Decryption in Rails
Homebrew Install Ruby Keg-Only Can't Find Gem
Why Does Rails 4.2 + Responders Keeps Telling Me to Add Responders to the Gemfile
Symbol#To_Proc with Custom Methods
How to Decode Q-Encoded Strings in Ruby
Using Nokogiri to Split Content on Br Tags
Ruby What Class Gets a Method When There Is No Explicit Receiver
Param Is Missing or the Value Is Empty
Optional Parens in Ruby for Method with Uppercase Start Letter
How to Use Same Browser Window for Automated Test Using Selenium-Webdriver (Ruby)
Install Cocoapods Failed on MAC
Problem Installing SQLite3-Ruby!
Uploading Files in Ruby on Rails
Ruby.Metaprogramming. Class_Eval
How to Set a Hook to Run Code at the End of a Ruby Class Definition