From 02ff496536e4054e25b6eaba79ff3bd117548eb9 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 31 Jul 2026 00:03:27 +0000 Subject: [PATCH] docs(justdummies): document ConstraintCall.Of's argument convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of's second parameter takes rendered text, not parameter names, and the distinction was only legible from the sites that use it: V(minimum) and Join(values) render a value, while "comparer" and "" stand in for an argument the library must not render. The two shapes read alike at a call site, so "comparer" invites nameof(comparer) — which compiles, produces the same string today, and quietly ties a user-facing message to a parameter identifier. ADR-0065 ties a constraint's name to its method through nameof, for reasons that stop at the name: a method name is a public symbol a rename must carry along. A stand-in is prose. Binding it to a symbol would let a rename local to one overload reword a diagnostic, and would leave the same constraint reading differently across the generators declaring it. Documentation only: no code, no message and no test changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SuSBsGG7wMPMnSeTHKZAom --- JustDummies/ConstraintCall.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/JustDummies/ConstraintCall.cs b/JustDummies/ConstraintCall.cs index 18ab1835..a9aec59a 100644 --- a/JustDummies/ConstraintCall.cs +++ b/JustDummies/ConstraintCall.cs @@ -56,6 +56,27 @@ internal sealed class ConstraintCall : IEquatable { /// A constraint whose arguments are rendered, including the common case of a constraint that takes none — /// which is this factory called with no (Zero(), Distinct()). /// + /// + /// + /// takes rendered text — what the reader of a conflict message sees + /// between the parentheses — never a parameter name. Two shapes reach it. The ordinary one is a value the + /// declaring generator rendered itself (V(minimum), Join(values)), giving + /// Between(0, 100). The other is a word standing in for an argument that has no useful rendering, + /// written where it reads better than the ellipsis would give: + /// Distinct(comparer) for an equality, ContainingAny(<generator>) for a recipe. + /// + /// + /// Such a stand-in is passed as the literal it is, and nameof(...) does not belong here even when + /// the parameter it would name happens to spell it — Distinct(IEqualityComparer<T>) passes + /// "comparer", not nameof(comparer). The rule differs from 's on + /// purpose: a method name is a public symbol the message must follow through a rename, whereas a stand-in + /// is prose whose resemblance to a parameter is a coincidence of good naming. Tying it to the symbol would + /// let a rename local to one overload silently reword a user-facing message, and would leave the same + /// constraint reading differently across the generators declaring it as soon as two of them named their + /// parameter differently. <generator> is that same convention where no identifier could have + /// been mistaken for it. + /// + /// /// The declaring method's name, passed as nameof(...). /// The arguments, each already rendered by the declaring generator. /// The constraint, rendered as name(argument, argument).