177

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?

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
cmhobbs
  • 2,469
  • 3
  • 24
  • 30

5 Answers5

162

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.

Soviut
  • 88,194
  • 49
  • 192
  • 260
Pan Thomakos
  • 34,082
  • 9
  • 88
  • 85
  • 3
    What do you mean by "bound" in "which cannot be instantiated without being bound to an upper level class"? – Andrew Grimm Jun 01 '11 at 03:01
  • Your second sentence cleared the air, that's EXACTLY the kind of explanation I was looking for. Thanks!!! – cmhobbs Jun 01 '11 at 03:14
  • 2
    @Andrew Grimm, I mean that you cannot instantiate the lower level class (`Car::Wheel`) without calling the upper level class (`Car`). In that sense it is 'bound' to the upper level class. You can also think of this as `Car::Wheel` cannot exist without `Car`. In that sense `Car::Wheel` is bound to `Car`. – Pan Thomakos Jun 01 '11 at 03:21
  • @pan..but we cant establish any relation between objects of inner class and objects of outer class, right?..for eg: between `Car.new` and `Car::Wheel.new` – rubyprince Jun 02 '11 at 18:46
  • 6
    @rubyprince, I'm not sure what you mean by establishing a relation between `Car.new` and `Car::Wheel.new`. You definitely don't need to initialize a `Car` object to initialize a `Car::Wheel` object in Ruby, but the `Car` class must be loaded and executed for `Car::Wheel` to be usable. – Pan Thomakos Jun 02 '11 at 19:08
  • 32
    @Pan, you are confusing Java *inner classes* and namespaced Ruby classes. A non-static Java nested class is called an *inner class* and it exists only within an instance of the outer class. There is a hidden field that allows outward references. *The Ruby inner class is simply namespaced and is not "bound" to the enclosing class in any way.* It is equivalent to a Java *static* *(nested)* class. Yes, the answer has a lot of votes but it is not completely accurate. – DigitalRoss Mar 12 '14 at 18:09
  • 3
    The use of the term "inner class" and the discussion of "Inner Classes in OOP" and binding is confusing, particularly for programmers with knowledge of Java (largely agreeing with @DigitalRoss here). Both of the OP's examples are just namespacing. – Tim Diggins Mar 18 '14 at 13:07
  • 8
    I have no idea how this answer got 60 upvotes, let alone did get accepted by the OP. There is literally not a single true statement in here. Ruby doesn't have nested classes like Beta or Newspeak do. There is absolutely no relation whatsoever between `Car` and `Car::Wheel`. Modules (and thus classes) are simply namespaces for constants, there is no such thing as a nested class or nested module in Ruby. – Jörg W Mittag Oct 16 '14 at 09:20
  • 2
    @JörgWMittag you might be splitting hairs on terminology with respect to inner classes, nested classes, etc., but I think if you re-read the question and answer you'll find that the posted answer does provide a solution to "why/when these techniques should be used". Additionally, you may be confused regarding the differences between `class Car::Wheel ; end` and `class Car ; class Wheel ; end ; end`. – Pan Thomakos Oct 16 '14 at 23:18
  • 4
    The only difference between the two is constant resolution (which is lexical, and thus obviously different because the two snippets are lexically different). There is, however, absolutely no difference between the two concerning the classes involved. There are simply two completely unrelated classes. Period. Ruby doesn't have nested/inner classes. Your definition of nested classes is correct, but it simply doesn't apply to Ruby, as you can trivially test: `Car::Wheel.new`. Boom. I have just constructed a `Wheel` object which isn't nested inside a `Car` object. – Jörg W Mittag Oct 17 '14 at 03:14
  • 5
    @JörgWMittag I see what you're saying. My intention was not to imply that you need a `Car` instance to instantiate `Car::Wheel` or that `Car::Wheel` can only be instantiated within a `Car` instance, but rather that `Car::Wheel` is namespaced under `Car` and hence conveys an additional relationship between the two. I think my answer aimed to clarify that aspect of Ruby, but I don't doubt that it fell short. If you would suggest some edits, I would be happy to modify the post to clarify this point and make the answer more useful. – Pan Thomakos Oct 18 '14 at 04:31
  • 13
    This post is highly misleading without reading the entire comment thread. – Nathan Aug 28 '15 at 20:59
58

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
Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • 19
    Please, pretty please, don't call this an inner class. It's not. The class `B` is *not* inside class `A`. The *constant* `B` is namespaced inside class `A`, but there is absolutely no relationship between the object referenced by `B` (which in this case just happens to be a class) and the class referenced by `A`. – Jörg W Mittag Oct 16 '14 at 09:23
  • 4
    Ok, "inner" terminology removed. Good point. For those who aren't following the argument above, the reason for the dispute is that when you do something like this in, say, Java, objects of the inner class (and here I'm using the term canonically) contain a reference to the outer class and the outer instance variables can be referenced by inner class methods. None of that happens in Ruby unless you link them with code. And you know, if that code was present in the, ahem, enclosing class, then I bet you could reasonably call Bar an *inner class.* – DigitalRoss Aug 10 '15 at 21:06
  • 2
    To me it is this statement that helps me the most when deciding between a module and a class: `You can't call new on a module.` -- so in basic terms if I just want to namespace some classes and never need to actually create an *instance* of the outer "class", then I'd use an outer module. But if I want to instantiate an instance of the wrapping/outer "class" then i would make it a Class instead of a Module. At least this makes sense to me. – FireDragon Dec 27 '18 at 23:44
  • 1
    @FireDragon Or another use case might be that you want a class that is a Factory, which subclasses inherit from, and your factory is responsible for creating instances of the subclasses. In that situation, your Factory cannot be a module because you cannot inherit from a module, so it's a parent class that you don't instantiate (and can 'namespace' it's children if you want, kind of like a module) – rmcsharry Jul 19 '19 at 11:10
15

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!

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • 3
    Twitter gem updated link: https://github.com/sferik/twitter/tree/master/lib/twitter – kode Mar 10 '13 at 17:44
13

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.

Timur Nugmanov
  • 803
  • 9
  • 16
3

In the addition to previous answers: Module in Ruby is a class

$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object
ceth
  • 44,198
  • 62
  • 180
  • 289
  • 12
    You'd be more accurate to say that 'class in Ruby is a module'! – Tim Diggins Mar 18 '14 at 13:05
  • 3
    Everything in Ruby may be an object, but calling module a class does not seem correct: irb(main):005:0> Class.ancestors.reverse => [BasicObject, Kernel, Object, Module, Class] – Chad M Mar 20 '15 at 06:56
  • 1
    and here we come to the definition of "is" – ahnbizcad Mar 01 '16 at 07:08
  • 2
    Note that modules can not be instantiated. I.e., it is not possible to create objects from a module. So modules, unlike classes, do not have a method `new`. So although you can say Modules are a class (lowercase), they are not the same thing as a Class (uppercase) :) – rmcsharry Jul 19 '19 at 11:13