In Ruby, how do you define a class method such as Shape.build with def self., and how does it differ from an instance method?
answer
- self in a class body
- called on the class object
- instances reach it via self.class
- subclasses inherit it too
- self is the receiving subclass
basics
~20 sWrite def self.build inside the class body, where self is the class, and call it as Shape.build. Instances do not have it; they call self.class.build. Subclasses inherit it, and inside it self is whichever class received the call.
solid answer
~30 sInside `class Shape ... end`, `self` is the class object `Shape`, so `def self.build` defines a method on that object: a **class method**, called as `Shape.build`. An instance method (`def area`) is called on objects made by `Shape.new`. The two do not mix: `Shape.new.build` raises `NoMethodError`, and an instance reaches class behaviour with `self.class.build`, which also picks the subclass's version. Class methods are inherited: with `class Circle < Shape`, `Circle.build(2)` works, and inside `build`, `self` is `Circle`, so a bare `new` there creates a Circle. That makes `def self.` methods the natural home for factories, parsers and per-class settings.
code
ruby · 15 linesclass Shape
def self.from_h(attrs)
new(**attrs)
end
end
class Square < Shape
def initialize(side:)
@side = side
end
def area = @side * @side
end
Square.from_h(side: 3).area # => 9go deeper
Define def self.build, call it on the class, and call it from an instance with self.class.build; know that instances do not have class methods.
Explain that self in a class body is the class object, so def self. defines a method on that object, and that inherited class methods see the subclass as self.
Use class-method factories that call a bare new so subclasses construct themselves, and keep per-class state behind class methods rather than scattered globals.
Judge how much behaviour belongs on classes at all: class-method factories and registries are convenient but become hidden global state when they hold mutable data.
## Where `def self.` comes from In Ruby a class is itself an object (an instance of `Class`), and inside the body of `class Shape ... end` the keyword `self` refers to that object. `def self.build` therefore defines a method whose receiver is `Shape` itself. Such methods are called **class methods**: ```ruby class Shape def self.kind = name.downcase.to_sym def self.build(*args) new(*args) end def label = "a #{self.class.kind}" end class Circle < Shape def initialize(radius) @radius = radius end end c = Circle.build(2) # a Circle: self in build was Circle c.label # => "a circle" Shape.kind # => :shape c.kind # NoMethodError ``` ## Class methods vs instance methods | | Class method | Instance method | |---|---|---| | Defined with | `def self.build` | `def label` | | Called on | the class: `Shape.build` | an object: `shape.label` | | `self` inside | the class that received the call | the object | | Instance variables inside | the class object's own `@vars` | the object's `@vars` | | Typical use | factories, parsing, lookups, settings | behaviour of one object | Key points behind the table: - An object does **not** get its class's class methods. `c.kind` raises `NoMethodError`, even though some other languages let an instance call a static member. - From an instance method, reach class behaviour with **`self.class.kind`**. Writing `Shape.kind` also works but always asks Shape, even when the object is a Circle. - A class method has no access to any particular instance's state; if it needs one, pass the object in. ## Inheritance and `self` Class methods are inherited down the class tree: `Circle.build` exists because `Shape.build` does. Inside the inherited method, `self` is the class that **received** the call, not the class that defined it. In the example, `new(*args)` inside `build` is really `self.new(*args)`, so `Circle.build(2)` makes a Circle and passes `2` to `Circle#initialize`. The same goes for `name`, which is why `Circle.build(2).label` says `"a circle"`. This is what makes class-method factories work across a hierarchy: one definition in the base class, correct objects for every subclass. ## Common mistakes 1. **Calling a class method on an instance.** `shape.build` is a `NoMethodError`; use `shape.class.build`. 2. **Hard-coding the base class.** Writing `Shape.new` inside `def self.build` returns a Shape even for `Circle.build`; use a bare `new` so `self` decides. 3. **Expecting instance variables to be shared.** `@count` inside a class method is the class object's variable; inside an instance method it is that object's. They are different variables that happen to share a name. 4. **Assuming `private` above it hides a class method.** A bare `private` section applies to instance methods; hiding a class method needs a separate mechanism, covered with visibility. ## Where class methods fit in practice Class methods are the right home for behaviour that belongs to the kind of thing rather than to one instance: - **Alternative constructors and factories**: `Shape.build`, `Square.from_h(side: 3)`, `Shape.parse(text)`. They end in a bare `new`, so subclasses construct themselves. - **Lookups**: finding or listing instances the class keeps track of. - **Per-class facts and settings**: `Circle.kind`, a default colour, a table name. Where these hold data, the data lives in the class object's own instance variables or in a class variable, and that choice has consequences of its own. What does not belong there: behaviour that needs one object's state. If a class method keeps asking for an object's fields, it probably wants to be an instance method. ## Other spellings you will meet `def Shape.build` also defines a class method but repeats the class name, which breaks if the class is renamed; RuboCop's `Style/ClassMethods` cop asks for `self.` instead. A `class << self` block is another way to define several class methods at once; how it works belongs to the singleton-class topic. ## Why interviewers ask it It checks that you see classes as objects, know that class and instance methods are separate sets, can call between them correctly, and understand that `self` in an inherited class method is the subclass. Those four facts explain almost every class-method bug a junior meets.
- Inside def self.build, why write new(*args) rather than Shape.new(*args)?A bare `new` is sent to `self`, which is whichever class received `build`. `Circle.build(2)` therefore creates a Circle. Writing `Shape.new` hard-codes the base class, so every subclass's factory would return a plain Shape and subclass constructors would never run.
- How does an instance method call a class method of its own class?Through `self.class`, as in `self.class.kind`. That sends the message to the object's actual class, so a Circle asks `Circle.kind` and picks up any override there. A bare `kind` would look for an instance method and raise `NameError` or `NoMethodError`.
saying these in an interview costs you the question
- An instance can call its class's class methods directly, as shape.build.
- Class methods are not inherited, so Circle.build fails unless Circle redefines it.
- Inside an inherited class method, self is always the class that defined it.
- @count in a class method and @count in an instance method are the same variable.