---
title: Methods
source: 'https://academia.sh/en/courses/ruby-fundamentals/methods'
course: 'Ruby Fundamentals'
language: en
updated: '2026-10-21T05:03:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Finds the responder of receiverless calls with method and owner'
    - 'Combines a default value, variadic arguments, and a keyword argument in one method definition'
    - 'Measures that a method defined with a top-level def is owned by Object and stays private'
---

# Methods

Receiverless calls live in the Kernel module; method definitions with default values, variadic arguments, and keyword arguments; implicit return; a top-level def is written into Object and stays private.

The previous lesson showed that `case` sends a message to the branch object when choosing a branch, and it left a question: when `format("%03d", 7)` or `puts "name"` is written, there is no receiver in sight. Where does the message go, and who answers it? The concept of a function was introduced in the Programming Fundamentals course (M01/K02); it is not repeated here. This lesson reads Ruby's methods with a single measure: who is the owner that handles a receiverless call?

## Who Handles a Receiverless Call

In the expression `format("%03d", 7)` there is no dot and no receiver. But we learned in the earlier lessons: in Ruby every call is a message, and a message has a receiver. When no receiver is written, the receiver is the object the code is running in at that moment. At the top level, this object is the main object of the file. The file below uses `defined?` to ask whether this call is a method, and `method` and `owner` to ask who owns it.

```ruby
# receiverless.rb — the responder of a receiverless call
puts defined?(format("%03d", 7))
puts method(:format).owner
puts method(:format).owner.instance_of?(Class)
puts format("%03d", 7)
```

```
method
Kernel
false
007
```

`format` is a method, and its owner is `Kernel`. `Kernel` is a module, not a `Class`, so `instance_of?(Class)` returned `false`. In this case the classification rule of the course counts the responder as a module. The top-level object of the file also reaches the `Kernel` methods, so even when no receiver is written, the call finds an owner.

**LB12.** In this lesson, a "method" is a unit of work that is defined with `def` or by the language and called by its name. `method(:name).owner` gives the owner of the method, that is, the class or module where its definition is found. The lookup chain itself (the order in which places are searched) is not measured in this course; only the result, the owner, is printed.

## Familiar Calls in Kernel

In the earlier lessons, `puts` and `p` were used without any explanation. The file below asks for the owner of all six calls.

```ruby
# kernel_calls.rb — the owner of receiverless calls
[:puts, :p, :format, :Integer, :raise, :block_given?].each do |name|
  printf("%-14s %s\n", name, method(name).owner)
end
```

```
puts           Kernel
p              Kernel
format         Kernel
Integer        Kernel
raise          Kernel
block_given?   Kernel
```

All six are in `Kernel`. `puts` and `p` write to the screen, `format` formats, `Integer` converts, `raise` raises an exception, and `block_given?` says whether a method has a block. They all look like "words of the language", but each is actually an ordinary method with a known owner. This differs from `if` and `while` in the previous lesson: those were syntax, and these are messages.

## Parameter Kinds and Implicit Return

We write our own method with `def`. The parameter list can hold required arguments, default values, variadic arguments, and keyword arguments together. Even when `return` is not written, the method returns the value of its last expression; this is called implicit return.

```ruby
# parameters.rb — parameter kinds and implicit return
def assemble(name, title = "mr", *extras, city: "north")
  "#{title} #{name} #{extras.size} #{city}"
end

puts assemble("pat")
puts assemble("pat", "dr", 1, 2, city: "south")
p method(:assemble).parameters
```

```
mr pat 0 north
dr pat 2 south
[[:req, :name], [:opt, :title], [:rest, :extras], [:key, :city]]
```

In the first call only `name` was given; `title` and `city` took their default values, and `extras` stayed empty. In the second call, `"dr"` overrode the default, `1` and `2` were collected into the `extras` array as variadic arguments, and `city:` was given as a keyword argument. `parameters` labels the kind of each one: `req` for required, `opt` for one with a default, `rest` for variadic, and `key` for keyword. There is no `return` in the method; the last expression, the string, was returned. The `#{...}` spelling inside the string is string interpolation.

## Methods That Take a Block

A block can be given to a method call with curly braces or `do ... end`. The method runs the block with `yield` and asks whether a block was given with `block_given?`. The owner of `block_given?` came out as `Kernel` two sections earlier: this too is an ordinary method. In a call without a block, the method can return a different value. What happens when a required argument is missing can also be measured.

```ruby
# block_receiving.rb — yield and block_given?
def repeat(count)
  return :empty unless block_given?
  count.times { |index| yield index }
  :done
end

p repeat(2) { |index| puts index }
p repeat(2)

begin
  repeat
rescue ArgumentError => e
  puts e.class
end
```

```
0
1
:done
:empty
ArgumentError
```

In the call with a block, the block ran twice (`0` and `1` were written) and the method returned `:done`. In the call without a block, `block_given?` was `false`, so the method returned early with `:empty`. The call that did not give the required `count` argument raised `ArgumentError`, and only its class was printed. So the interface of a method is not only its parameter list; the block is also part of the call, but it does not appear in the parameter list of the method. If the block is named explicitly in the form `&block`, it enters the list; the `:block` label in a later section shows this.

## Returning Multiple Values

In Ruby, a method returns a single value, but that value can be an array, and the caller can split the array into pieces in one step. This also works together with implicit return: the last expression of the method is a two-element array in square brackets.

```ruby
# multiple_returns.rb — a method that returns an array and multiple assignment
def divide(a, b)
  [a / b, a % b]
end

result = divide(17, 5)
p result
quotient, remainder = divide(17, 5)
puts quotient
puts remainder
puts result.class
```

```
[3, 2]
3
2
Array
```

The method returned a single `Array`. The spelling `quotient, remainder = ...` unpacks this array into two names; this is not a feature of methods but the spelling of assignment, and it ties back to the syntax observation of the earlier lesson. So the return value of the method and how the caller reads it remain two separate jobs.

## Probing the Parameter Kinds

This section measures the parameter kinds. In the method below, seven parameter kinds stand together: required, with a default, splat (`*rest`), required keyword, optional keyword, keyword collector (`**opts`), and block taker (`&block`). The measure is the method describing itself: `method(:name).parameters` reports the parameter list of the method, and `arity` reports how many arguments it expects. The axis is the owner; the owner of the defined method is printed too.

```ruby
# parameter_kinds.rb — parameter kinds and arity
def example(a, b = 2, *rest, c:, d: 4, **opts, &block); end
puts method(:example).parameters.inspect
puts method(:example).arity
def two(a, b); end
puts method(:two).arity
def with_default(a, b = 1); end
puts method(:with_default).arity
puts method(:example).owner
```

```
[[:req, :a], [:opt, :b], [:rest, :rest], [:keyreq, :c], [:key, :d], [:keyrest, :opts], [:block, :block]]
-3
2
-2
Object
```

The `parameters` output gave each parameter with a kind label: `:req` is required, `:opt` has a default, `:rest` is splat, `:keyreq` is required keyword, `:key` is optional keyword, `:keyrest` is the keyword collector, and `:block` is the block-taking parameter. The `arity` values showed three separate cases: `2` for `two`, which has two required parameters, `-2` for `with_default`, which has one required and one with a default, and `-3` for `example`. A negative number means "not a fixed number of arguments"; there are optional or unbounded parameters. The absolute value is one more than the minimum number of arguments needed: `-2` asks for at least one, and `-3` asks for at least two. In `example`, next to the required `a` there are a required keyword `c:` and optional parameters, and the result was `-3`. A required keyword parameter counts as a single extra argument in this calculation. The rule was measured here only on these three methods. On the last line the owner of `example` came out as `Object`: the responder of a method defined at the top level is `Object`.

**LB13.** The sign of the `arity` value was read only on these three methods. That the same rule holds for other parameter layouts was not measured.

```ruby
# key_error.rb — missing and extra keywords, and implicit return
def box(width:, height: 1)
  width * height
end
begin
  box(height: 2)
rescue ArgumentError => e
  puts e.class
end
begin
  box(width: 1, depth: 3)
rescue ArgumentError => e
  puts e.class
end
puts box(width: 3)
def implicit
  42
end
def explicit
  return 42
end
puts implicit == explicit
def early(n)
  return :negative if n < 0
  :positive
end
puts early(-1).inspect
puts early(1).inspect
puts method(:box).owner
```

```
ArgumentError
ArgumentError
3
true
:negative
:positive
Object
```

`box(height: 2)` was called without the required `width:` keyword and raised `ArgumentError`; `box(width: 1, depth: 3)` raised `ArgumentError` again because an undefined keyword was given. In both cases only `e.class` was printed, because the text of an error message may depend on the version. The valid call `box(width: 3)` gave `3`. These three results show that keyword parameters are a contract: a missing one and an extra one are both rejected with the same class. In the second half, implicit return was compared with `return`: `implicit` and `explicit` returned the same `42`. `return` is not redundant; the `early(-1)` line shows that `return` ends the method early, and the `early(1)` line shows that the value of the last expression is the return value. The owner of the method came out as `Object` for `box` as well. So the return value is determined in two ways: by the last expression of the method, or by the value given with `return`.

## Holding a Method as an Object

A method can also be turned into an object. The call `method(:name)` gives the method as an object of the `Method` class; this object can be called, converted into a block, and asked for its receiver and owner. The question of this section is who a method defined at the top level belongs to, and whether it appears public when asked from the outside. The axis is the owner; we print the receiver and the owner together.

```ruby
# method_object.rb — holding a method as an object
def square(n)
  n * n
end
m = method(:square)
puts m.class
puts m.call(4)
puts [1, 2, 3].map(&m).inspect
puts m.name.inspect
puts m.receiver == self
puts m.owner
puts send(:square, 3)
puts respond_to?(:square, true)
puts respond_to?(:square)
```

```
Method
16
[1, 4, 9]
:square
true
Object
9
true
false
```

`method(:square)` gave a `Method` object. `m.call(4)` returned `16`; because the method is an object, it could be held in a variable and called later. The expression `[1, 2, 3].map(&m)` converted the method object into a block with `&` and gave `[1, 4, 9]`. The name `:square` is a symbol. `m.receiver == self` was `true`: the receiver of a method defined at the top level is the top-level `main` object, and `m.owner` came out as `Object`. This also explains why a receiverless call `square(3)` works: when no receiver is written, the message goes to the current `self` object.

The last three lines measure the difference in access. `send(:square, 3)` gave `9`, so sending the message by its name worked. `respond_to?(:square, true)` printed `true`, and `respond_to?(:square)` printed `false`. The second argument says to count private methods too; the question without an argument counts only public methods, and the top-level method is not among them. So `square` is defined in the `Object` class and is not counted among the public methods, but it can be reached with a receiverless call or with `send`. What a call written with an explicit receiver would give was not measured here. This difference shows that the `Object` owner and the access level are two separate properties.

**LB14.** That a top-level method is private was inferred from the `respond_to?` pair; the access level was not verified with another measurement (such as `private_methods`).

## Splat on the Call Side

The `*` and `**` marks seen in a parameter definition do the opposite on the call side: they expand an array or a hash into the argument list. This section measures both directions together. The axis is the owner; how many arguments a method can expect is printed with `arity`, and who defined it with `owner`.

```ruby
# splat_call.rb — * and ** on the call side
def add_all(*numbers)
  numbers.sum
end
list = [1, 2, 3]
puts add_all(*list)
puts add_all(list.first, *list.last(2))
puts add_all
def options(**o)
  o.inspect
end
h = {a: 1}
puts options(**h)
puts options(b: 2, **h)
def single(x)
  x
end
puts single([1, 2]).inspect
puts method(:add_all).arity
puts method(:add_all).owner
```

```
6
6
0
{a: 1}
{b: 2, a: 1}
[1, 2]
-1
Object
```

`add_all(*list)` expanded the array into three separate arguments and gave `6`. The spelling `add_all(list.first, *list.last(2))` combined one single argument with two expanded ones and again came out as `6`. The call `add_all` with no arguments gave `0`: a splat parameter accepts an empty array. `options(**h)` expanded the hash into keyword arguments and gave `{a: 1}`; `options(b: 2, **h)` combined an explicitly written key with an expanded key and gave `{b: 2, a: 1}`. In the merge, the explicitly written key came first.

The contrasting example is the call `single([1, 2])`: an array given without a star stayed a single argument, and the method returned `[1, 2]`. So expansion is written on purpose on the call side; where there is no star, an array is an array. `method(:add_all).arity` gave `-1`: no fixed number of arguments is expected, and at least zero are needed. The owner came out as `Object`. The spelling of the language expands the arguments of a call, but what receives the expanded list is still the parameter definition of the method; when the two sides match, the call works. The parameter definition and the call side use the same mark, but their directions are opposite: in a definition `*` collects the arguments, and in a call `*` expands the array.

## The Bounding Measurement

The responder of this lesson is a module, but there is a slip: does the owner of a method we write ourselves also become a module? When `def` is written at the top level of a file, where does the method go? The measurement below asks this.

```ruby
# top_level.rb — a top-level def is written into Object and is private
def square(n)
  n * n
end

puts method(:square).owner
puts method(:square).owner.instance_of?(Class)
puts respond_to?(:square)
puts respond_to?(:square, true)
puts square(4)
```

```
Object
true
false
true
16
```

A top-level `def square` writes the method into the `Object` class. `Object` is an instance of `Class` (`true`), so in this case the responder is not a module but a class. The method also stays private: `respond_to?(:square)` returned `false`, because private methods are invisible when asked from the outside. `respond_to?(:square, true)` includes private methods and gives `true`. The receiverless call `square(4)` returned `16`, because when no receiver is written, private methods are reachable too. The methods in `Kernel` are owned by a module; our own `def` is owned by `Object`, that is, by a class.

## Summary

- In a receiverless call, the receiver is the object the code is running in at that moment; the `Kernel` module answers the call `format("%03d", 7)`.
- `puts`, `p`, `format`, `Integer`, `raise`, and `block_given?` are ordinary methods, and the owner of all six is `Kernel`.
- A method can carry required arguments, default values, variadic arguments, and keyword arguments together; if `return` is not written, the last expression is returned.
- A top-level `def` writes the method into the `Object` class and leaves it private; `respond_to?(:square)` returns `false` and `respond_to?(:square, true)` returns `true`.
- The responder of this lesson is a module: the owner of receiverless calls is the `Kernel` module, while the owner of a top-level method we write ourselves is `Object`, which is a class.
- `method(:name).parameters` names the seven parameter kinds in the measured method; a missing or undefined keyword gives `ArgumentError`; on the call side `*` and `**` expand an array and a hash into arguments.

## Next Step

The owners of methods were measured, and we saw where a receiverless call goes. Next come strings: when `"name".to_sym` is written, a string turns into a symbol, and a symbol is also an object. Once a string turns into a symbol, who answers the message, and does a magic comment change that? The next lesson, Symbols and Strings, measures this.
