In Ruby, what do BankAccount.class, Class.superclass and Module.superclass return, and what does that say about classes?
answer
- a class is an instance
- Class inherits from Module
- Class.class is Class
- new lives on Class, not Module
- Class.new builds anonymous classes
basics
~20 sBankAccount.class is Class, Class.superclass is Module and Module.superclass is Object. Every class is an ordinary object, an instance of Class, and every class is also a Module, which is why classes hold methods and constants.
solid answer
~40 s`BankAccount.class` returns `Class`, `Class.superclass` returns `Module`, and `Module.superclass` returns `Object`, whose superclass is `BasicObject`. So a class is an object like any other: it can be stored in a variable, passed to a method, and sent messages such as `new`, `name` and `instance_methods`. Because `Class < Module`, a class has the module machinery for holding methods and constants, plus what `Class` adds: `new`, `allocate` and `superclass`. That is also why a module cannot be instantiated: `Comparable` is an instance of `Module`, which has no `new` instance method. `Class.new(parent) { ... }` builds a class at run time; it stays anonymous, with `name` returning `nil`, until it is assigned to a constant. The loop closes at the top: `Class.class` is `Class` itself.
code
ruby · 14 linesclass BankAccount; end
BankAccount.class # => Class
BankAccount.is_a?(Module) # => true
Class.superclass # => Module
Class.class # => Class
Comparable.class # => Module
Comparable.new # NoMethodError: new is defined on Class, not Module
anon = Class.new(BankAccount)
anon.name # => nil
SavingsAccount = anon
anon.name # => "SavingsAccount"go deeper
Recall that a class is an object, an instance of Class, and that Class.superclass is Module.
Explain instance-of versus inherits-from, why a module has no new, and how Class.new creates a class that stays anonymous until a constant names it.
Use the model to reason about real code: classes passed as arguments to factories, reopened class bodies, and throwaway anonymous subclasses in tests that must not leak constants.
Judge when run-time class creation earns its place versus plain class definitions, given its cost to readability, stack traces and tooling that expects named constants.
## Classes are instances of Class In Ruby, **everything you can name is an object**, and classes are no exception. `class BankAccount ... end` creates an object whose class is `Class` and stores it in the constant `BankAccount`. That object is what receives the message when you write `BankAccount.new`. ```ruby BankAccount.class # => Class BankAccount.superclass # => Object Class.superclass # => Module Module.superclass # => Object Object.superclass # => BasicObject BasicObject.superclass # => nil Class.class # => Class ``` Two separate relations are at work, and interviewers like to see them kept apart: - **Instance-of** (`obj.class`): `BankAccount` is an instance of `Class`, and so are `Module`, `Object` and `Class` itself. - **Inherits-from** (`klass.superclass`): `Class` inherits from `Module`, which inherits from `Object`, which inherits from `BasicObject`. The rdoc for `Class` draws this as a diagram in which classes, modules and objects are interrelated, and every metaclass is itself an instance of `Class`. ## What Class < Module gives a class Because `Class` is a subclass of `Module`, every class *is a* module: | Capability | Comes from | Available on a module? | |---|---|---| | holding instance methods, constants | `Module` | yes | | `instance_methods`, `const_get`, `name` | `Module` | yes | | `new`, `allocate` | `Class` | no | | `superclass`, `subclasses` | `Class` | no | That table answers two common questions: 1. **Why can't I write `Comparable.new`?** `Comparable` is an instance of `Module`. The method `new` that builds instances is defined on `Class`, so the lookup fails and Ruby raises `NoMethodError`. (`Module.new`, called on the class `Module`, does exist: it creates a new anonymous module.) 2. **Why can't I `include` a class?** `Class` removes the hooks that mixing in relies on, and `include` checks that each argument really is a module, raising `TypeError` for a class. ## Building a class at run time Since a class is just an object, you can create one with a method call: ```ruby OverdraftError = Class.new(StandardError) do def message = "balance would go negative" end anon = Class.new(Object) anon.name # => nil ``` - `Class.new(superclass)` defaults the superclass to `Object`. - The block is evaluated in the context of the new class, like a `class` body, so `def` inside it defines instance methods. - The class is **anonymous** until assigned to a constant. `name` returns `nil`, and `inspect` shows something like `#<Class:0x000...>`. Assigning it to a constant such as `OverdraftError` gives it that name permanently. ## Why it matters in practice - **Classes as values.** A method can take a class argument and call `.new` on it, for example a factory that receives `BankAccount` or `SavingsAccount`. - **Class methods are methods on an object.** `def self.open(...)` inside `BankAccount` defines a method on the class object itself, which is why it is called as `BankAccount.open`. - **Reopening.** Because a class is a long-lived object bound to a constant, a second `class BankAccount` body reopens the same object rather than creating a new class. - **Anonymous classes in tests** let you build throwaway subclasses without polluting the constant namespace. ## Traps in the wording - **`BankAccount.class` is not `Object`.** `Object` is the superclass of `BankAccount`, not its class; mixing up the two relations is the most common slip. - **`Module` is not a subclass of `Class`.** The inheritance runs the other way: `Class < Module`, so every class is a module but not every module is a class. - **`Class.class` is `Class`.** The chain of instance-of relations ends in a loop at `Class`, while the superclass chain ends at `BasicObject`, whose superclass is `nil`. The short version for an interview: a class is an object that happens to be an instance of `Class`, and `Class` is a kind of `Module` that adds the ability to create instances and to have a superclass.
- In Ruby, what is the difference between BankAccount.class and BankAccount.superclass?`class` answers "what is this object an instance of?" and returns `Class`, because `BankAccount` is a class object. `superclass` answers "what does this class inherit from?" and returns `Object` for a class declared without `<`. The two chains only meet at the top of the hierarchy.
- In Ruby, when is an anonymous class created with Class.new given a name?The first time it is assigned to a constant, for example `OverdraftError = Class.new(StandardError)`. Until then `name` returns `nil`; afterwards it returns the constant's path, and reassigning the class to another constant later does not rename it.
saying these in an interview costs you the question
- Classes are compile-time declarations, not objects you can pass around
- Module inherits from Class, so modules are special classes
- A module can be instantiated with new like a class
- BankAccount.class returns Object because every class inherits from Object
- An anonymous class from Class.new has an empty string as its name