In Ruby 4.0, why might a file's # frozen_string_literal: true magic comment be ignored, and what syntax rules must magic comments follow?
answer
- per file, top of file
- before any code token
- key: value, nothing else
- dashes equal underscores, any case
- encoding on line 1 or 2
basics
~20 sMagic comments are read only from the comments at the top of a file, before any code. A frozen_string_literal line after a require, with trailing text, without its colon or with a non-boolean value is ignored.
solid answer
~50 sA magic comment is a `# key: value` directive that the parser reads from the **top of a file**, and it affects only that file. In Ruby 4.0, Prism applies these rules to `frozen_string_literal`. It must come **before any code token**; after `require "json"` it is ignored, and `ruby -w` warns `'frozen_string_literal' is ignored after any tokens`. The key is **case-insensitive, and dashes equal underscores**, so `# Frozen-String-Literal: true` counts. The value must be `true` or `false` in any case; anything else is ignored with an `invalid value` warning under `-w`. And the comment must hold **only** the directive: trailing text (`# frozen_string_literal: true # perf`) or a missing colon makes it an ordinary comment, with no warning. Several directives can share one line in Emacs style: `# -*- coding: utf-8; frozen_string_literal: true -*-`. An `encoding` directive must be on line 1, or line 2 after a shebang.
code
ruby · 6 lines#!/usr/bin/env ruby
# frozen_string_literal: true
require "json"
p "loan".frozen? # => true: the line 2 directive covers the filego deeper
Know that magic comments are # key: value lines at the top of a file and that each file needs its own.
Explain the placement rules, especially that frozen_string_literal must precede any code and encoding must be on line 1 or 2.
Diagnose an ignored directive with ruby -w and a probe, including the silent cases such as trailing text or a missing colon.
Decide how the team guarantees directives are present and correct across files, preferably through tooling that fails CI rather than review.
## What a magic comment is Most comments are ignored, but a few written as `# key: value` are **directives** that change how the parser treats the file. Ruby 4.0's default parser, Prism, recognises four keys: - `encoding` (or `coding`): the source encoding of the file; - `frozen_string_literal`: how string literals in the file are allocated; - `warn_indent`: whether mismatched indentation of `end` produces warnings; - `shareable_constant_value`: how values assigned to constants are treated. What each directive *does* is a topic for its own feature. This question is about **where and how** they must be written, because a misplaced directive is silently ignored and the file then behaves differently from what its author believes. Each directive affects **only the file it appears in**, never the files that file requires. ## Where each directive must appear | Directive | Where it must appear | If it is elsewhere | |---|---|---| | `encoding` / `coding` | line 1, or line 2 when line 1 is a `#!` shebang | not treated as an encoding directive | | `frozen_string_literal` | in the comments at the top of the file, before any code | ignored; `ruby -w` warns it is ignored after any tokens | | `warn_indent` | any comment line; affects the code after it | not applicable | | `shareable_constant_value` | a comment-only line; may repeat, affecting later constants in the same scope | ignored with a verbose warning when code shares the line | ## Syntax rules the parser applies 1. **Key, colon, value.** The comment is `key: value`; spaces around the colon are fine, but `frozen_string_literal = true` has no colon and is not a directive. 2. **Flexible key spelling.** Keys are matched case-insensitively, and each `-` is treated as `_`, so `Frozen-String-Literal` matches. 3. **Boolean values.** `true` and `false` are accepted in any case. Any other value, such as `yes`, is ignored and reported as an invalid value when warnings are on. 4. **Nothing else in the comment.** In the plain form, only whitespace may follow the value; `# frozen_string_literal: true # perf` is therefore an ordinary comment. 5. **Emacs style for several directives.** Between `-*-` markers, directives are separated by `;`: `# -*- coding: utf-8; frozen_string_literal: true -*-`. ## Diagnosing an ignored directive 1. Run the file with `ruby -w`. Prism's verbose warnings catch a `frozen_string_literal` placed after code and an invalid value. 2. If there is no warning, check the spelling rules: a missing colon or trailing text produces no warning at all. 3. Check the position: a `require` line, a `module` line or any other code above the directive disables it. 4. Check the file: a directive in `app.rb` does nothing for `lib/loan.rb`; each file needs its own. 5. Confirm the effect at run time with a probe such as `p "x".frozen?` placed in the same file. ## Why the rules are strict - Prism accepts `frozen_string_literal` only before the first code token, which keeps a whole file under one setting instead of switching halfway through. - The encoding must be known before the parser can read the rest of the bytes, so it is pinned to the first line (or the line after a shebang). - Requiring the whole comment to be the directive keeps ordinary prose comments, which often contain colons, from being mistaken for directives. ## Interview summary 1. Directives live in the comments at the top of the file and apply to that file only. 2. `frozen_string_literal` must precede all code; `encoding` must be on line 1 or 2. 3. The comment is `key: value` and nothing else, or several pairs inside `-*-` markers. 4. Keys ignore case and treat dashes as underscores; boolean values must be `true` or `false`. 5. `ruby -w` reveals some mistakes, but a missing colon or trailing text is silent. ## Common setups - A shebang on line 1 followed by `# frozen_string_literal: true` on line 2 is valid. - A licence header made only of comments, and blank lines, may come first; code may not. - Linters can require the directive in every file; which files a team enforces is a tooling decision rather than a language rule.
- Does a frozen_string_literal comment in a file affect the files it requires?No. Magic comments are per file: the parser applies a directive only to the file it is reading. A file loaded with `require` is parsed on its own and needs its own directive. Ruby's `--enable=frozen-string-literal` command-line option is the way to change the default for every file, and it is disabled by default.
- Why does shareable_constant_value behave differently from frozen_string_literal in placement?It is scoped rather than file-wide: it may appear several times in a file, must sit on a comment-only line, and affects only the constants assigned after it in the same scope. A `frozen_string_literal` directive, by contrast, is read once from the top of the file and is ignored after any code.
saying these in an interview costs you the question
- A magic comment works anywhere in the file as long as it starts with #
- The key must be written exactly frozen_string_literal in lowercase
- A magic comment in the main script applies to every file it requires
- Adding an explanatory note after the value on the same line is harmless
- The encoding comment can go anywhere in the first comment block