Multiple Inheritance in Ruby? - ruby

I thought that Ruby only allowed single inheritance besides mixin. However, when I have class Square that inherits class Thing, Thing in turn inherits Object by default.
class Thing
end
class Square < Thing
end
Doesn't this represent multiple inheritance?

I think you are taking the meaning of multiple inheritance in a wrong way. Probably what you have in mind as multiple inheritance is like this:
class A inherits class B
class B inherits class C
If so, then that is wrong. That is not what multiple inheritance is, and Ruby has no problem with that. What multiple inheritance really means is this:
class A inherits class B
class A inherits class C
And you surely cannot do this in Ruby.

No, multi inheritance means one class have more than one parent class. For example in ruby you can have that behavior with modules like:
class Thing
include MathFunctions
include Taggable
include Persistence
end
So in this example Thing class would have some methods from MathFunctions module, Taggable and Persistence, that wouldn't be possible using simple class inheritance.

Multiple inheritance - This is absolutely not possible in ruby not even with modules.
multilevel inheritance - This is what is possible even with the modules.
Why ?
Modules acts as an absolute superclasses to the class that includes them.
Ex1 :
class A
end
class B < A
end
This is a normal inheritance chain, and you can check this by ancestors.
B.ancestors => B -> A -> Object -> ..
Inheritance with Modules -
Ex2 :
module B
end
class A
include B
end
inheritance chain for above example -
B.ancestors => B -> A -> Object -> ..
Which is exactly same as a Ex1. That means all the methods in module B can override the methods in A, And it acts as a real class inheritance.
Ex3 :
module B
def name
p "this is B"
end
end
module C
def name
p "this is C"
end
end
class A
include B
include C
end
A.ancestors => A -> C -> B -> Object -> ..
if you see the last example even though two different modules are included they are in a single inheritance chain where B is a superclass of C, C is a superclass of A.
so,
A.new.name => "this is C"
if you remove the name method from module C, above code will return "this is B". which is same as inheriting a class.
so,
At any point there is only one multilevel inheritance chain in ruby, which nullifies having multiple direct parent to the class.

If class B inherits from class A,
then instances of B have the behaviors of both class A and class B
class A
end
class B < A
attr_accessor :editor
end
Ruby has single inheritance, i.e. each class has one and only one parent class.
Ruby can simulate multiple inheritance using Modules(MIXINs)
module A
def a1
end
def a2
end
end
module B
def b1
end
def b2
end
end
class Sample
include A
include B
def s1
end
end
samp=Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
Module A consists of the methods a1 and a2. Module B consists of the methods b1 and b2. The class Sample includes both modules A and B. The class Sample can access all four methods, namely, a1, a2, b1, and b2. Therefore, you can see that the class Sample inherits from both the modules. Thus you can say the class Sample shows multiple inheritance or a mixin.

Related

Why module included outside the class adds instance methods to class's objects

I am experimenting with the Ruby include keyword as shown below:
module A
def show
puts "working"
end
end
include A
class E
end
class D
end
e = E.new
d = D.new
e.show
d.show
o = Object.new
puts o.respond_to?("show")
******************************output****************
working
working
true
I was expecting output to be undefined method but it's giving me the proper output. I have also observed that the show method defined in module A is becoming an instance method of Object.
Why are these methods becoming instance methods of the class Object?
Please help in understanding this concept.
Because instances of class Class inherit from Object.
Thus, modules, included into Object are available to instances of Class's instances (instances of your E and D classes).
class A
end
module B
def test; :hi end
end
#=> test
include B
#=> Object
A.new.test
#=> :hi
Object.new.test
#=> :hi
Having include B written in the top-level means include'ing B into Object.
include B is the outermost context is equivalent to:
class Object
include B
end
The only class, whose instances do not share module B's methods is BasicObject.

Nested classes in Ruby

I can't figure out how to initialize a class from a parent class variable. I'm trying to accomplish this:
x = A::B.new('my string')
myObject = x::C.new(**params)
and the program I'm calling is organized similar to:
module A
...<stuff>...
class B
...<stuff>....
class C < B
...<stuff>...
end
end
end
I want to initialize the class C after initializing the parent class B. That way, I can have access to class B's variables and methods from class C.
When I try to execute my program, I get:
"#<A::B:0x...............>" is not a class/module (TypeError)
Can anyone point me in the right direction for initializing nested classes like this?
You can't construct an instance from an instance - the whole module hierarchy is only applicable to modules and classes. Since x is neither, the parser has no idea what :: is supposed to do.
The idea behind nested classes is that they are namespaced within the parent class, no more, no less. In effect, class B acts like a module prefix to class C, but there's no inherent relationship between them (by being nested alone; you do inherit C from B in your example, which is what gives you the relationship), and certainly not between an instance of B and the class C
Instead, I would recommend constructing a C directly with 'my string', then calling #super in the initialize method, like so:
myObject = A::B::C.new('my string', **params)
and in the implementation:
module A
class B
def initialize(some_string)
#some_string = some_string
end
class C < B
def initialize(str, params)
super(str)
...
end
end
end
end
As the error message suggests, the namespace operator :: can only be applied to a class/module. If x were the class A::B, then x::C should work. It does not make sense to apply ::C on an instance of A::B.
You need to apply the :: to x's class, not x itself. So you just need a call to the class method:
x = A::B.new('my string')
myObject = x.class::C.new(**params)
For example, this sort of thing:
module A
class B
class C
end
end
end
pancakes = A::B.new
eggs = pancakes.class::C.new
puts pancakes.inspect
puts eggs.inspect
gives you something like this:
#<A::B:0x007faea90b6a58>
#<A::B::C:0x007faea90b6a30>

What is best practice to extend class in Ruby?

I want to understand difference between following
module XYZ
class A
end
class B
end
end
Does class C inherit both class A and B, or I have to extend it using < ?
module YZZ
include XYZ
class C < A
end
end
What happens when I do following? Does it now include all classes, or just class A ?
module YZZ
extend XYZ
class C < A
end
end
What is the best way to extend class C from A ?
How can I extend class C using both A and B ?
How can I only include class A?
Ad 1., yes, C inherits both A and B when you use #include. #extend applies to class methods.
Ad 2. class C < A, think about it that A is merely a constant, that is assigned an object
of instance Class as value. So, of course, C becomes its subclass.
Ad 3. When you use #extend inside the 'module' statement, self is the module itself, and XYZ
basically gets included in its sigleton class.
As for your three bulleted questions in the end, I do not understand the first one. What is "extend class C from A"? Will class C < XYZ::A do? As for the second bulleted question, you can extend C "using both A and B" simply by C.extend( XYZ ). As for "how can you only include class A", there is no simple way to only include part of a module. If you plan to include class A separately, if it has its own concern to solve even without B, put it in a separate module and include that one. That's called separation of concerns. If you just want to cherry-pick, you could do:
module Something
A = XYZ::A
end
And there you have a constant Something::A pointing to the same class as XYZ::A.
This should work:
module XYZ
class A
end
class B < A
end
end
Then for including the XYZ module and extending C from A:
module ABC
include XYZ
class C < A
end
end

How do I get the parent's class name in Ruby

Let assume I have a classes A and B where B inherits A. How do I print parent class name in B
class A
end
class B < A
end
Some things I have tried
>> B.new.class #=> B #which is correct
>> B.new.parent #=> Undefined method `parent`
>> B.parent #=> Object
>> B.parent.class #=> Class
Thanks :)
class A
end
class B < A
end
B.superclass # => A
B.superclass.name # => "A"
If you want the full ancestor stack try:
object.class.ancestors
For instance:
> a = Array.new
=> []
> a.class.ancestors
=> [Array, Enumerable, Object, Kernel, BasicObject]
In case google brings anyone here who's working in Rails, what you may want instead is base_class, as superclass will traverse the ActiveRecord inheritance structure as well.
class A < ActiveRecord::Base
end
class B < A
end
> A.superclass
=> ActiveRecord::Base
> B.superclass
=> A
> A.base_class
=> A
> B.base_class
=> A
Even further...
class C < B
end
> C.base_class
=> A
In other words, base_class gives you the top of the inheritance tree but limited to the context of your application. Fair warning though, as far as Rails is concerned "your application" includes any gems you're using, so if you have a model that subclasses something defined in a gem, base_class will return the gem's class, not yours.
Given an object (Instantiated Class) you can derive the parent Class
>> x = B.new
>> x.class.superclass.name
=>"A"
The term you're looking for is superclass. And indeed you can do B.superclass to get A. (You can also do B.ancestors to get a list of all the classes and modules it inherits from — something like [B, A, Object, Kernel, BasicObject].)
Inheritance is a relation between two classes. Inheritance create a
parent child relationship between classes. It is a mechanism for code
reuse and to allow independent extensions of the original software via
public classes and interfaces.The benefit of inheritance is that
classes lower down the hierarchy get the features of those higher up,
but can also add specific features of their own.
In Ruby, a class can only inherit from a single other class. (i.e. a class can inherit from a class that inherits from another class which inherits from another class, but a single class can not inherit from many classes at once). The BasicObject class is the parent class of all classes in Ruby. Its methods are therefore available to all objects unless explicitly overridden.
Ruby overcome the single class inheritance at once by using the mixin.
I will try to explain with an example.
module Mux
def sam
p "I am an module"
end
end
class A
include Mux
end
class B < A
end
class C < B
end
class D < A
end
You can trace by using class_name.superclass.name and do this process unless you found BasicOject in this hierarchy. BasicObject is super class o every classes. lets see suppose we want to see class C hierarchy tree.
C.superclass
=> B
B.superclass
=> A
A.superclass
=> Object
Object.superclass
=> BasicObject
You can see the whole hierarchy of class C. Point to note using this approach you will not find modules that are included or prepended in the parent classes.
There is another approach to find complete hierarchy including modules. According to Ruby doc ancestors. Returns a list of modules included/prepended in mod (including mod itself).
C.ancestors
=> [C, B, A, Mux, Object, Kernel, BasicObject]
Here, Mux and Kernel are Modules.
http://rubylearning.com/satishtalim/ruby_inheritance.html
https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

Mixing methods into the current class' eigenclass

I'm implementing a semi-duplicate Rails pipeline by refactoring an existing Ruby class, say A, which extends ActiveRecord, to have a module, say M, with common functionality, then to be mixed into two similar AR classes, now shallow wrappers.
When taking the meat of A and mincing it into M, A's instance methods simply become methods in M, and A's class methods go into a ClassMethods submodule of M, to be mixed back into A at class-level with a self.included hook of M and extend, via the well-known idiom.
However, A is not just any class -- we use some of its class methods from DelayedJob, which does not naturally understand class methods; hence we moved some of the original class methods of A into A's eigenclass, defining them as
class A
...
def old_plain_vanilla_class_method
...
end
class << self
def new_eigenclassed_class_method
...
end
...
end
...
end
The question now is, how do we represent that in M, so it mixes right back into A's eigenclass?
Not sure that I understand you well (more code please), but can't you do something like this:
module M
def M.included(c)
class << c.class
def foo
"foo"
end
end
end
end

Resources