In IRB, what does the underscore variable _ hold, and what do __ and IRB.conf[:EVAL_HISTORY] add?
answer
- the last evaluated value
- also the last exception raised
- a local variable IRB sets
- __ only with EVAL_HISTORY
- __[-2], __[line_no]
basics
~10 sIn IRB, _ holds the value of the last evaluated expression, or the exception object if that input raised. __ is the numbered history of results, and exists only after setting IRB.conf[:EVAL_HISTORY] or conf.eval_history.
solid answer
~40 sAfter every evaluation IRB sets a local variable `_` in the session's binding to the result, so `CSV.parse(text); _.size` works without naming the result first. If the input raised, `_` holds the **exception object**, so `_.backtrace` or `_.message` is one step away. `__` is different: it is only defined once evaluation history is on (`IRB.conf[:EVAL_HISTORY] = 10` in `.irbrc`, or `conf.eval_history = 10` in the session). Then `__` prints the stored results with their line numbers, `__[12]` returns the result of line 12 and `__[-2]` the second most recent. `_` is a plain local, so assigning `_ = 1` yourself only lasts until the next evaluation overwrites it.
code
ruby · 12 linesirb(main):001> CSV.parse("name,email\nAda,\n", headers: true)
=>
#<CSV::Table mode:col_or_row row_count:2>
name,email
Ada,
irb(main):002> rows = _
irb(main):003> rows.first.fetch("phone")
...in 'CSV::Row#fetch': key not found: phone (KeyError)
irb(main):004> _.class
=> KeyError
irb(main):005> conf.eval_history = 5
=> 5go deeper
Recall that _ is the last result in IRB and use it to keep an expensive value you forgot to assign.
Explain that _ is a local IRB sets after every evaluation, including to the exception on failure, and that __ needs EVAL_HISTORY.
Use _ on exceptions to inspect backtraces during an incident console session instead of re-running side-effecting code.
Treat console conveniences as part of a safe investigation workflow: capture results once, avoid re-running writes, and record what was run.
## The problem _ solves In a console you often evaluate something expensive — parsing a file, loading records — and only afterwards realise you wanted to keep the result. Re-running it wastes time and may repeat side effects. IRB's answer is the **underscore variable**. ## What _ is and when it changes After each input is evaluated, IRB calls `set_last_value` on its context, which does two things: - stores the result as `conf.last_value`; - sets a **local variable named `_`** in the session's binding to that result. So `_` always refers to the most recent result, whatever it was. Details worth knowing: - **Assignments count.** `rows = CSV.parse(text)` makes `_` the parsed array too. - **Exceptions count.** When an input raises, IRB prints the error and then sets `_` to the **exception object**. `_.class`, `_.message` and `_.backtrace.first(5)` are then available without wrapping anything in `begin/rescue`. - **A new session starts with `_` as `nil`**, because the workspace initialises it. - **It is just a local.** Nothing stops you writing `_ = 42`, but the next evaluation replaces it — including the evaluation of that very assignment, whose result is 42. Two neighbouring features use it: the `copy` command with no argument copies `_` to the clipboard, and the Ruby convention of naming an unused block parameter `_` is unrelated and unaffected — block parameters shadow the outer local inside the block. ## __ and evaluation history `__` (two underscores) is an opt-in extension. By default IRB keeps no history of results and `__` is not defined. You turn it on with: - `IRB.conf[:EVAL_HISTORY] = n` in an rc file such as `~/.irbrc`, or - `conf.eval_history = n` at the prompt, at any time. `n` is how many results to keep; `0` keeps them all. Once enabled: | Expression | Returns | |---|---| | `__` | A listing of the stored results, each with its input line number. | | `__[12]` | The result of input line 12, or `nil` if it is not in the history. | | `__[-2]` | The second most recent stored result. | | `__[0]` | Always `nil`. | IRB validates the setting at startup: a non-integer `EVAL_HISTORY` in an rc file stops IRB with a `TypeError`. ## A note on the docs vs the code IRB's own guide describes `_` as undefined until evaluation history is enabled. The IRB source disagrees: `_` is set on every evaluation regardless, and only `__` depends on `EVAL_HISTORY`. When the two disagree, trust what the console does. ## Where _ does not help - Inside an `irb:rdbg` session started with IRB's `debug` command, IRB documents `_` as unsupported, because the debug gem drives evaluation there. - In your program's own code `_` has no special meaning; this is a console feature, not a Ruby global. ## A typical use 1. `CSV.parse(File.read("users.csv"), headers: true)` — slow, and you forgot to assign it. 2. `rows = _` — keep it. 3. `rows.count { it["email"].nil? }` — ask your question. 4. If step 3 raises, `_.backtrace.first` shows where.
- After an input raises NoMethodError in IRB, what does _ contain?The `NoMethodError` instance itself. IRB rescues the exception, prints it, and then sets the local `_` to the exception object, so `_.message`, `_.receiver` or `_.backtrace` can be inspected immediately without re-running the failing code inside a `begin/rescue`.
- How do you make __ available in every IRB session rather than typing conf.eval_history each time?Put `IRB.conf[:EVAL_HISTORY] = 20` (any integer; `0` keeps everything) in an IRB rc file such as `~/.irbrc`. IRB reads it at startup and defines `__` with that many stored results. A non-integer value fails IRB's config validation with a `TypeError`.
saying these in an interview costs you the question
- _ is a Ruby global that also works inside normal program code.
- _ is left unchanged when the last input raised an exception.
- __ is available in every IRB session with no configuration.
- IRB.conf[:EVAL_HISTORY] = 0 turns evaluation history off.
- _ skips assignments, so after x = 5 it still holds the earlier value.