// or a Nesting /* … */, and a Run of /// Before an Item Is Its Documentation — Prose the Parser Keeps and the Contract Does Not CarryStatus: Accepted
Date: October 3, 2026
History: the records this one replaces are archived in docs/history/adr; read them only for how the decision was reached
Answers: what a comment is besides // (a block of code commented out, a
paragraph above a function, a note inside an argument list), whether a block
comment nests, and whether the language has a doc comment, how it is spelled,
and what reads it
Related:
ADR-251 D2 (the contract carries no prose; std.contracts keeps its sentences as # comments);
ADR-296 (a grammar { … } block’s vocabulary is its own page, so a /* inside one, or inside a dsl … eod body, is text);
ADR-024 (the ledger is what a consumer’s compiler reads about a dependency);
Part I chapter 2 (the comment rule as a program follows it); Part III 13.5 (the contract)
Which forms of comment does the language have, and is one of them an item’s documentation — and if so, what reads it?
A line comment is enough for a sentence beside a statement and not for commenting out a block of code that already holds a comment, for a paragraph above a function, or for a note inside an argument list. And a package’s surface is read by people and tools that never open its source; whether a sentence written above a function belongs to that function has to be a rule, not a convention, before anything can carry it.
| Language / tool | Its answer | Source |
|---|---|---|
| C, JavaScript | /* … */ exists and does not nest: the first */ closes it |
from memory, not checked |
| Rust | /* … */ nests; /// and /** … */ are doc comments, //! and /*! inner doc comments |
from memory, not checked |
Most languages with both // and /// |
//// is an ordinary comment |
from memory, not checked |
What does not transfer: Rust has two spellings of a doc comment, and a reader of this language would have to learn which one a project uses. One spelling is enough.
| Question | Option | Verdict |
|---|---|---|
| Block comment | none (only //) |
rejected: no way to comment out a block or annotate inside an argument list |
/* … */ that does not nest (C) |
rejected: commenting out code that already holds a block comment means hunting for the inner close | |
/* … */ that nests (Rust) |
chosen (D1, D2) | |
| Unclosed comment | reported where the input ran out | rejected: that is the end of the file, which points at nothing the reader must fix |
reported at the /* that opened it |
chosen (D2) | |
| Doc comment | /** … */ as well as /// |
rejected: two spellings; a block comment stays a comment wherever it stands (D3) |
/// before an item |
chosen (D4) | |
| Markup | @param and directives the compiler reads |
rejected: prose only (D6) |
| Where the prose goes | a doc column in the contract |
rejected: the compiler never reads it, and a reworded sentence would fail --locked on a contract that had not changed (ADR-251 D2) |
| the source only | chosen (D5) |
/* opens a comment that */ closes, across lines, anywhere whitespace may stand.A block comment may stand between any two tokens, inside an argument list,
inside a grammar { … } block, across as many lines as it needs. It is
whitespace to the parser, as a line comment is. A /* inside a string
literal is text, not a comment; a // inside a block comment is comment, not
a second comment.
/* a /* b */ c */ is one comment that ends at the second */, so a block of
code that already holds a block comment can be commented out without hunting
for the inner close. An unclosed block comment is a parse error reported at the
/* that opened it — at the outer opening when a nested one is what is
missing — because that is where the reader must fix it, not the end of the file
where the parser gave up.
/** … */ and /*! … */ are block comments and nothing more.A comment that begins with two stars, or with a star and a bang, is a comment. The language’s one documentation form is D4’s, and it is not spelled with a block comment.
/// lines immediately before an item is that item’s documentation, and the parser keeps it./// The status line for a response code, as HTTP/1.1 writes it.
///
/// An unknown code is `500 Internal Server Error`, which is what a
/// server owes a client it cannot answer.
pub fn status_line(status: i32) -> String { … }
An item here is a fn (a method and a trait method included), a struct, an
enum, a trait, a field and a variant. The text is the run’s lines with the
slashes and one space taken off, joined by their own line breaks. Anywhere else
/// is an ordinary comment, and //// is an ordinary comment everywhere.
An ordinary comment between the run and the item does not end the run: a comment is not code, so the prose is still about the item below it, and a sentence for whoever reaches the item followed by a note for whoever reads the source is a shape worth allowing. What ends a run is code: prose with a statement or another item between it and the next item belongs to nothing, and an item does not inherit the prose of the one above it.
A doc comment stays in the source. The compiler does not copy it into
nikaia.contracts, for a public item or any other, and a ledger that still has
a doc key is refused as a key nothing reads; std.contracts, which is
written by hand, keeps its sentences as # comments above the entries they
are about (ADR-251 D2). Whether a dependency’s documentation needs
a way to travel to a consumer is left to something that addresses the
contract’s entries rather than living in them (§6).
No @param, no directive, no link the compiler resolves, and no refusal for a
wrong one. A doc comment on a private item is kept exactly as one on a public
item is: the source is where both live (D5).
Because the contract carries no prose (D5), rewording a /// leaves
nikaia.contracts byte for byte the same: --locked does not fail on it, and
the diff narration, which says what broke a caller, has nothing to say. An
edited comment shows only in the record of what the contract was derived from,
which names the sources it was built from (Part III 13.5).
*/ hidden behind a // or inside a string is not taken for the close./// lines by the time an item matches; and the item asks for its prose at
its first byte, against a position in the input rather than a flag, so that
the alternatives of an item that fail after consuming tokens cannot spoil
the answer.nikaia doc: its output and where it writes.grammar block, whose vocabulary is its own page
(ADR-296).