skip to content

Defining Methods Dynamically

define_method builds methods from a block or Method at run time, capturing loop values as closures, and define_singleton_method does it per object. Interviewers ask what it costs over def.

on this pageshow

explore

questions

5

In Ruby, how does define_method differ from def in how the method name is chosen and what the method body can see?

level: middleimportance: must knowfreq 55%

answer

  1. literal name versus a value
  2. scope gate versus closure
  3. yield sees the wrong block
  4. |&blk| to take the caller's block
  5. private applies in the class body

basics

~20 s

def takes a literal name and starts a fresh local scope. define_method takes the name as a Symbol or String value and uses a block as the body, so the body is a closure that sees the defining scope's local variables.

solid answer

~40 s

`def` fixes the name in the source and is a scope gate: the body cannot see the class body's local variables. `define_method(name) { ... }` takes the name as data and runs a block as the body, so the body closes over locals such as a loop variable, while `self` is still the instance. Both return the name as a Symbol, and both honour a preceding `private` when called in the class body. The traps: the block is made strict like a lambda, and `yield` or `block_given?` inside it refer to the defining context's block, not the caller's; declare `|&blk|` to receive the caller's block. In Ruby 4.0 a `yield` in such a block directly in a class body is even a `SyntaxError`.

code

ruby · 10 lines
ruby
class Feed
  def initialize(lines) = @lines = lines

  define_method(:each_line) do |&blk|
    @lines.each(&blk)
  end
end

Feed.new(["a", "b"]).each_line { puts it }
# prints a, then b

go deeper

for a junior

Recall that define_method takes the name as a value and a block as the body, while def has a literal name.

for a middle

Explain scope gate versus closure, the strict lambda arity, and why yield needs a |&blk| parameter instead.

for a senior

Show judgement: def by default, define_method only when the name is data or the body must capture a value, and keep generated code greppable.

for a principal

Set a team rule for when generated methods are worth the lost searchability and the closures they keep alive.

## Two ways to add an instance method Ruby has two everyday ways to put an instance method into a class: - **`def name ... end`** — a keyword. The name is written literally in the source, and the body is compiled as a method. - **`define_method(name) { |args| ... }`** — a method of `Module`, called on the class. The name is a **Symbol or String value**, and the body is a **block**. Both produce an ordinary instance method that callers use in exactly the same way, and both return the method's name as a Symbol. The differences are in what the body can see and how the name is chosen. ## Scope: a gate versus a closure `def` is a **scope gate**: the method body starts with a fresh set of local variables and cannot see locals of the class body around it. A block is a **closure**: it keeps access to the local variables that were in scope where it was written. ```ruby class Price rate = 1.2 # a local of the class body def gross_def(net) = net * rate # NameError when called: rate is not visible define_method(:gross) { |net| net * rate } # sees rate end Price.new.gross(10) # => 12.0 ``` That is the main reason to reach for `define_method`: the body needs a value that only exists while the class is being built, such as a loop variable or a configuration entry. ## The name as data Because `define_method` takes the name as an argument, the name can be computed: `define_method(:"#{field}_changed?")`. `def` cannot do this; its name is fixed when the file is parsed. A String name is converted to a Symbol. ## Where the two behave differently | Aspect | `def` | `define_method` with a block | |---|---|---| | name | literal in the source | any Symbol or String value | | outer locals | not visible | visible (closure) | | `self` in the body | the instance | the instance | | `yield`, `block_given?` | the caller's block | the block of the *defining* context | | arity | as declared | strict, like a lambda | | `return` | leaves the method | leaves the method | | visibility under `private` in the class body | private | private | | return value | name as a Symbol | name as a Symbol | Three rows need a word. 1. **`yield` does not reach the caller's block.** Inside the block body, `yield` and `block_given?` refer to whatever block the *surrounding* code received. To accept the caller's block, declare it as a block parameter: `define_method(:each_line) { |&blk| lines.each(&blk) }`. In Ruby 4.0, whose default parser is Prism, a `yield` inside a `define_method` block written directly in a class body does not even parse: it is a `SyntaxError` ("Invalid yield"). 2. **Arity is strict.** The block is turned into a lambda, so calling with the wrong number of arguments raises `ArgumentError`, exactly like a `def` method. 3. **Visibility follows where it is called.** Called in a class body after a bare `private`, `define_method` creates a private method, just as `def` would. Called from outside, as `Order.define_method(...)`, it creates a public method. `Module#define_method` has been public since Ruby 2.5; older gems wrote `send(:define_method, ...)` because it used to be private. ## When to use which - Prefer **`def`** whenever the name is known when you write the code. It is faster to read, found by a text search, and it has no closure to keep alive. - Use **`define_method`** when the name comes from data (a list of fields, statuses or formats) or the body must capture a value from the defining scope. - If you find yourself generating one method, you probably wanted `def`. ## What an interviewer is listening for The expected core is: the name is dynamic and the body is a closure, while `def` has a literal name and a fresh scope. A stronger answer mentions the `yield` trap and the `|&blk|` fix, and that `private` applies when `define_method` runs inside the class body. The best answers add the maintenance cost: generated methods do not appear in a text search, so keep the generating loop short and next to the list it reads.

  • Why does older gem code call send(:define_method, ...) on a class?
    Before Ruby 2.5, `Module#define_method` was private, so code outside the class body had to reach it with `send`. Since 2.5 it is public, and `SomeClass.define_method(:x) { ... }` works directly. The `send` form still runs but only obscures intent in Ruby 4.0 code.
  • Does a method made by define_method after a bare private in the class body end up private?
    Yes. When `define_method` runs in the class body, it picks up the current default visibility, so after `private` the method is private, just like a `def` there. When it is called from elsewhere, for example `Order.define_method(:x) { }` from a helper, the method is public.

saying these in an interview costs you the question

  • define_method bodies cannot see the class body's local variables
  • yield inside a define_method block reaches the caller's block
  • define_method ignores private, so its methods are always public
  • define_method returns the new Method object, not a Symbol
  • a define_method body runs with self set to the class
open as a page

In Ruby, how would you generate paid?, shipped? and cancelled? predicate methods on an Order class from a list of its statuses?

level: juniorimportance: should knowfreq 42%

basics

~10 s

Loop over a frozen STATUSES list with each and call define_method(:"#{s}?") { status == s } for every entry. Each iteration's block captures its own s, so every predicate compares against its own status.

open as a page

In Ruby, what changes when define_method receives a Proc, a lambda or an UnboundMethod as the body instead of a block?

level: middleimportance: should knowfreq 30%

basics

~20 s

A Proc or lambda body is copied and given lambda semantics, so arity is strict and return leaves the method. An UnboundMethod body reuses an existing definition, but only from the same class, an ancestor or a module; otherwise TypeError.

open as a page

In Ruby, what does define_singleton_method do, and when would you use it instead of define_method?

level: middleimportance: should knowfreq 28%

basics

~20 s

define_singleton_method adds a method to one object's singleton class, so only that object gets it. Called on a class object it creates a class method, which makes it the tool for generating class-level method families from a list.

open as a page

In CRuby 4.0, why can a method generated with define_method cost more than one written with def, and when does that difference matter?

level: seniorimportance: should knowfreq 30%

basics

~20 s

A define_method body is a closure: it keeps its whole defining scope alive, shares captured variables across calls, and YJIT compiles fewer call shapes for it, such as calls passing a block. Only hot paths, big closures or Ractor code justify rewriting.

open as a page