Ruby: nesting classes in classes same as nesting classes in modules? - ruby

In Ruby, one can declare classes like
class A
class B
end
end
and then instantiate the inner class like A::B.new.
Does B have some sort of special relationship with A (as is the case in Java) or is A just its namespace? In other words, is nesting a class in a class the same as nesting it in a module?

This is one of those times when you should really just fire up irb and try it.
Yes, a class can be defined within another class. Since a class's superclass is Module (i.e. Class extends Module), they can do almost everything a Module can. A notable exception is that you cannot include (mixin) a class.
That said, there's very little reason to actually use this design pattern. It is more likely that A and B can be considered siblings. There is no need to arbitrarily namespace until you are blue in the face. If you are more than 3 levels deep, stop and consider refactoring.
A better design pattern for this example might be:
module Alphabet
class A; end
class B; end
end
For something more complicated, this continues to work nicely using Mixins:
module Animals
class Dog
include Walking
end
module Walking
# some methods pertaining to the ability to walk
end
end

Yes, it's essentially the same as nesting in module. Nested class does not have any kind of special relationship to the class it's nested in.

Yes and...no. A Module can't be instantiated whereas a class can, so there is a difference in nesting a class within a Module vs. using a class nested within a class.
For example: You cannot instantiate an object of Ford here (i.e. Cobra, F-150, Mustang, etc.) because you cannot instantiate a module,.
`module Ford
class Engine
...
end
end`
But you can have an instance of the class Ford as well as instances of Ford engines with using nested classes like so:
`class Ford
class Engine
##actions = ['list', 'find', 'add', 'quit']
def self.actions; ##actions; end
end
def self.truck_exists?
#Some more stuff here
end
end`

Classes (and Modules) have different usages:
Namespace: when you define a class (or module) inside another class (or module), you have to use a different notation outside the defining class to reach the inner class or module.
Template for instances: There modules and classes behave totally (well mostly) different.
Inheritance: You may extend a class, so you inherit all its attributes and methods, which works for modules as well. Or you may include a module (not: a class) to add its methods (and attributes) to your scope. Ruby plays here tricks by mixin the module in the class hierarchy.
So in the context of using name spaces, they are the same. However I would all the time use modules (only), but that is more a matter of style. The best book on this topic is in my opinion "Metaprogramming Ruby" by Paolo Perrotta.

Related

Ruby inheritance and typing

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.

What criteria justifies using a Module over a Class in Ruby?

I'm reading my ruby book. Looking at the code below,
module Destroy
def destroy(anyObject)
#anyObject = anyObject
puts "I will destroy the object: #{anyObject}"
end
end
class User
include Destroy
attr_accessor :name, :email
def initialize(name,email)
#name = name
#email = email
end
end
my_info = User.new("Bob","Bob#example.com")
puts "So your name is: #{my_info.name} and you have email #{my_info.email}"
user = User.new("john","john#example.com")
user.destroy("blah")
I could've just created another method inside my class. Why would I want to do this? Why would I want to use a module? It's not like embedding this into other classes is any easier than just using normal inheritance.
You can think of a module and the methods and constants inside of it as more of providing utility functions and actions that you can include to other objects as you see fit. For example, if you wanted to use destroy function in the objects Foo and Bar you would do similarly:
class Foo
include Destroy
# other code below
end
class Bar
include Destroy
# other code below
end
Now any Foo or Bar object has access to all the methods or constants inside of destroy.
Modules define a namespace, a sandbox in which your methods and constants can play without having to worry about being stepped on by other methods and constants. The ruby docs goes into more depth about this and includes a good example practical of when you would want to use it as seen below:
module Debug
def whoAmI?
"#{self.type.name} (\##{self.id}): #{self.to_s}"
end
end
class Phonograph
include Debug
# ...
end
class EightTrack
include Debug
# ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI? » "Phonograph (#537766170): West End Blues"
et.whoAmI? » "EightTrack (#537765860): Surrealistic Pillow"
In this example, every class that includes Debug has access to the method whoAmI? and other methods and constants that Debug includes without having to redefine it for every class.
Some programming languages such as C++, Perl, and Python allow one class to inherit from multiple other classes; that is called multiple inheritance. Ruby does not support multiple inheritance. That means each class can only inherit from one other class. However, there are cases where a class would benefit by acquiring methods defined within multiple other classes. That is made possible by using a construct called module.
A module is somewhat similar to a class, except it does not support inheritance, nor instantiating. It is mostly used as a container for storing multiple methods. One way to use a module is to employ an include or extend statement within a class. That way, the class gains access to all methods and objects defined within the module. It is said that the module is mixed in the class. So, a mixin is just a module included in a class. A single module can be mixed in multiple classes, and a single class can mix in multiple modules; thus, any limitations imposed by Ruby's single inheritance model are eliminated by the mixin feature.
Modules can also be used for namespacing. That is explained in this post at the Practicing Ruby website.
You are writing a module in the same file as the class, but not necessarily inside the class, but anyway.
For me there are 3 reasons to use a module(more details here):
Modules provide a namespace and prevent name clashes.
Modules implement the mixin facility.
When you have a very complex and dense class, you can split it into
modules and include them into the main class.
Your example is fairly simple, it would indeed make more sense to write the method in the class itself, but try to imagine a complex scenario.

When to use nested classes and classes nested in modules?

I'm pretty familiar with when to use subclasses and modules, but more recently I've been seeing nested classes like this:
class Foo
class Bar
# do some useful things
end
end
As well as classes nested in modules like so:
module Baz
class Quux
# more code
end
end
Either documentation and articles are sparse or I'm not educated on the subject enough to grope for the right search terms, but I can't seem to locate much information on the topic.
Could somebody provide examples or links to posts on why/when those techniques would be used?
Other OOP languages have inner classes which cannot be instantiated without being bound to an upper level class. For instance, in Java,
class Car {
class Wheel { }
}
only methods in the Car class can create Wheels.
Ruby doesn’t have that behaviour.
In Ruby,
class Car
class Wheel
end
end
differs from
class Car
end
class Wheel
end
only in the name of the class Wheel vs. Car::Wheel. This difference in name can make explicit to programmers that the Car::Wheel class can only represent a car wheel, as opposed to a general wheel. Nesting class definitions in Ruby is a matter of preference, but it serves a purpose in the sense that it more strongly enforces a contract between the two classes and in doing so conveys more information about them and their uses.
But to the Ruby interpreter, it’s only a difference in name.
As for your second observation, classes nested inside of modules are generally used to namespace the classes. For instance:
module ActiveRecord
class Base
end
end
differs from
module ActionMailer
class Base
end
end
Although this is not the only use of classes nested inside of modules, it is generally the most common.
In Ruby, defining a nested class is similar to defining a class in a module. It doesn't actually force an association between the classes, it just makes a namespace for the constants. (Class and Module names are constants.)
The accepted answer wasn't correct about anything. In the example below I create an instance of the lexically enclosed class without an instance of the enclosing class ever existing.
class A; class B; end; end
A::B.new
The advantages are the same as those for modules: encapsulation, grouping code used in only one place, and placing code closer to where it is used. A large project might have one outer module that occurs over and over in each source file and contains a lot of class definitions. When the various frameworks and library codes all do this, then they contribute only one name each to the top level, reducing the chance of conflicts. Prosaic, to be sure, but that's why they are used.
Using a class instead of a module to define the outer namespace might make sense in a one-file program or script, or if you already use the top level class for something, or if you are actually going to add code to link the classes together in true inner-class style. Ruby doesn't have inner classes but nothing stops you from creating about the same behavior in code. Referencing the outer objects from the inner ones will still require dotting in from the instance of the outer object but nesting the classes will suggest that this is what you might be doing. A carefully modularized program might always create the enclosing classes first, and they might reasonably be decomposed with nested or inner classes. You can't call new on a module.
You can use the general pattern even for scripts, where the namespace isn't terribly needed, just for fun and practice...
#!/usr/bin/env ruby
class A
class Realwork_A
...
end
class Realwork_B
...
end
def run
...
end
self
end.new.run
You probably want to use this to group your classes into a module. Sort of a namespace thing.
for example the Twitter gem uses namespaces to achieve this:
Twitter::Client.new
Twitter::Search.new
So both Client and Search classes live under the Twitter module.
If you want to check the sources, the code for both classes can be found here and here.
Hope this helps!
There is yet another difference between nested classes and nested modules in Ruby prior to 2.5 that other answers failed to cover that I feel must be mentioned here. It is the lookup process.
In short: due to top level constant lookup in Ruby prior to 2.5, Ruby may end up looking for your nested class in the wrong place (in Object in particular) if you use nested classes.
In Ruby prior to 2.5:
Nested class structure:
Suppose you have a class X, with nested class Y, or X::Y. And then you have a top level class named also Y. If X::Y is not loaded, then following happens when you call X::Y:
Having not found Y in X, Ruby will try to look it up in ancestors of X. Since X is a class and not a module, it has ancestors, among which are [Object, Kernel, BasicObject]. So, it tries to look for Y in Object, where it finds it successfully.Yet it is the top level Y and not X::Y.
You will get this warning:
warning: toplevel constant Y referenced by X::Y
Nested module structure:
Suppose in the previous example X is a module and not a class.A module only has itself as ancestor: X.ancestors would produce [X].
In this case, Ruby won't be able to look for Y in one of ancestors of X and will throw a NameError. Rails (or any other framework with autoloading) will try to load X::Y after that.
See this article for more information: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Top level constant lookup removed.You may use nested classes without fear of encountering this bug.
In the addition to previous answers: Module in Ruby is a class
$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object

ruby nested classes and modules

I am familiar with the concept of nesting classes and modules within another module and grouping them in a namespace. What is the idea / purpose behind
Nesting classes within another class
class A
class B
def method_B
...
end
end
end
Nesting modules within another class
class A
module c
def method_c
...
end
end
end
thanks,
ash
Classes are also namespaces, so it's the same idea. Class is a subclass of Module, so if you get it in the context of modules, you also get it in the context of classes.
It is all about grouping related concerns while exposing sensible semantics. As an example of number 1 an HTTP::Request (Request class embedded in a larger HTTP protocol class) is a quite different thing from an FTP::Request. With modules it enables the common ruby idiom of Behavior::InstanceMethods and Behavior::ClassMethods for handling mixins.

ruby inheritance vs mixins

In Ruby, since you can include multiple mixins but only extend one class, it seems like mixins would be preferred over inheritance.
My question: if you're writing code which must be extended/included to be useful, why would you ever make it a class? Or put another way, why wouldn't you always make it a module?
I can only think of one reason why you'd want a class, and that is if you need to instantiate the class. In the case of ActiveRecord::Base, however, you never instantiate it directly. So shouldn't it have been a module instead?
I just read about this topic in The Well-Grounded Rubyist (great book, by the way). The author does a better job of explaining than I would so I'll quote him:
No single rule or formula always results in the right design. But it’s useful to keep a
couple of considerations in mind when you’re making class-versus-module decisions:
Modules don’t have instances. It follows that entities or things are generally best
modeled in classes, and characteristics or properties of entities or things are
best encapsulated in modules. Correspondingly, as noted in section 4.1.1, class
names tend to be nouns, whereas module names are often adjectives (Stack
versus Stacklike).
A class can have only one superclass, but it can mix in as many modules as it wants. If
you’re using inheritance, give priority to creating a sensible superclass/subclass
relationship. Don’t use up a class’s one and only superclass relationship to
endow the class with what might turn out to be just one of several sets of characteristics.
Summing up these rules in one example, here is what you should not do:
module Vehicle
...
class SelfPropelling
...
class Truck < SelfPropelling
include Vehicle
...
Rather, you should do this:
module SelfPropelling
...
class Vehicle
include SelfPropelling
...
class Truck < Vehicle
...
The second version models the entities and properties much more neatly. Truck
descends from Vehicle (which makes sense), whereas SelfPropelling is a characteristic of vehicles (at least, all those we care about in this model of the world)—a characteristic that is passed on to trucks by virtue of Truck being a descendant, or specialized
form, of Vehicle.
I think mixins are a great idea, but there's another problem here that nobody has mentioned: namespace collisions. Consider:
module A
HELLO = "hi"
def sayhi
puts HELLO
end
end
module B
HELLO = "you stink"
def sayhi
puts HELLO
end
end
class C
include A
include B
end
c = C.new
c.sayhi
Which one wins? In Ruby, it turns out the be the latter, module B, because you included it after module A. Now, it's easy to avoid this problem: make sure all of module A and module B's constants and methods are in unlikely namespaces. The problem is that the compiler doesn't warn you at all when collisions happen.
I argue that this behavior does not scale to large teams of programmers-- you shouldn't assume that the person implementing class C knows about every name in scope. Ruby will even let you override a constant or method of a different type. I'm not sure that could ever be considered correct behavior.
My take: Modules are for sharing behavior, while classes are for modeling relationships between objects. You technically could just make everything an instance of Object and mix in whatever modules you want to get the desired set of behaviors, but that would be a poor, haphazard and rather unreadable design.
The answer to your question is largely contextual. Distilling pubb's observation, the choice is primarily driven by the domain under consideration.
And yes, ActiveRecord should have been included rather than extended by a subclass. Another ORM - datamapper - precisely achieves that!
I like Andy Gaskell's answer very much - just wanted to add that yes, ActiveRecord should not use inheritance, but rather include a module to add the behavior (mostly persistence) to a model/class. ActiveRecord is simply using the wrong paradigm.
For the same reason, I very much like MongoId over MongoMapper, because it leaves the developer the chance to use inheritance as a way of modelling something meaningful in the problem domain.
It's sad that pretty much nobody in the Rails community is using "Ruby inheritance" the way it's supposed to be used - to define class hierarchies, not just to add behavior.
The best way I understand mixins are as virtual classes. Mixins are "virtual classes" that have been injected in a class's or module's ancestor chain.
When we use "include" and pass it a module, it adds the module to the ancestor chain right before the class that we are inheriting from:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Every object in Ruby also has a singleton class. Methods added to this singleton class can be directly called on the object and so they act as "class" methods. When we use "extend" on an object and pass the object a module, we are adding the methods of the module to the singleton class of the object:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
We can access the singleton class with the singleton_class method:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby provides some hooks for modules when they are being mixed into classes/modules. included is a hook method provided by Ruby which gets called whenever you include a module in some module or class. Just like included, there is an associated extended hook for extend. It will be called when a module is extended by another module or class.
module M
def self.included(target)
puts "included into #{target}"
end
def self.extended(target)
puts "extended into #{target}"
end
end
class MyClass
include M
end
class MyClass2
extend M
end
This creates an interesting pattern that developers could use:
module M
def self.included(target)
target.send(:include, InstanceMethods)
target.extend ClassMethods
target.class_eval do
a_class_method
end
end
module InstanceMethods
def an_instance_method
end
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
class MyClass
include M
# a_class_method called
end
As you can see, this single module is adding instance methods, "class" methods, and acting directly on the target class (calling a_class_method() in this case).
ActiveSupport::Concern encapsulates this pattern. Here's the same module rewritten to use ActiveSupport::Concern:
module M
extend ActiveSupport::Concern
included do
a_class_method
end
def an_instance_method
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
Right now, I'm thinking about the template design pattern. It just wouldn't feel right with a module.

Resources