The problem is that the most natural naming convention for APIs that use parameter packs is singular for the internal parameter name, and plural for the external argument label. However, doc comments for function parameters are typically written in terms of the internal parameter name. The language design for parameter packs includes a contextual each keyword that must be used when referencing parameter packs to make it syntactically clear in the code which values are packs versus normal scalar values:
struct Variable<Value> {}
/// Binds the given variables to the given input values, where the _i_th
/// variable is bound to the _i_th input.
func bind<each Input>(
variables variable: repeat Variable<each Input>,
to input: repeat each Input
) {
// Iterate over each element of the 'variable' and 'input' parameter packs,
// binding each variable to each input at each iteration.
repeat (each variable).bind(to: each input)
}
// Example call-site. Under substitution, `bind` invokes the following calls:
//
// x.bind(to: 1)
// y.bind(to: "hello")
bind(variables: x, y, to: 1, "hello")
The SE-0393 review surfaced a suggestion to allow or require writing each in doc comments to match the spelling of parameter pack references everywhere else, and to clarify in documentation that the function accepts a list of arguments in the form of a pack, e.g.:
struct Variable<Value> {}
/// Binds the given variables to the given input values, where the _i_th
/// variable is bound to the _i_th input.
///
/// - Parameter each variable: the list of variables to bind.
/// - Parameter each input: the list of input values to bind each variable to.
func bind<each Input>(
variables variable: repeat Variable<each Input>,
to input: repeat each Input
)
I like this suggestion, because it means everywhere a parameter pack is written, including both source code and documentation, it uses the each keyword, which helps encourage the idea that uses of parameter packs in a function signature are in terms of an individual element within the pack.
the format of “- Parameters” / “- Parameter” is completely unspecified and implementation-defined, and i recall some popular packages (e.g. swift-system) already fail validation when trying to apply “common sense” rules for markdown semantics.
we have similar problems with “aside blocks” which are also unspecified and implementation-defined (the most popular implementation currently being the swift-markdown package). and i will also add that i think it is questionable for swift-markdown to be doing markdown parsing and markdown semantics in the same pass, in my opinion this is already a layering violation.
to summarize:
markdown is completely opaque to the following layers of the documentation stack:
compiler (AST)
SymbolGraphGen
right now, it is the responsibility of higher-level tooling (e.g. DocC, Jazzy, project-specific tooling etc.) to define semantics for markdown documentation. are we sure we want swift itself to take on this responsibility? (keep in mind, markdown†is not the only format people use to write documentation.)
if we do want to take ownership of markdown semantics at the language level, what is the bigger roadmap here? do we have a plan for standardizing:
aside blocks? (easy difficulty)
“throws” blocks? (medium difficulty)
snippet embedding? (easy difficulty)
symbol links? (VERY HARD difficulty)
if we do want to have a language-level standard for markdown documentation, how will we emit diagnostics for malformed markdown documentation? the compiler does not understand markdown. (and not all doccomments are written in markdown.) and swift-markdown just delegates to cmark-gfm. is cmark-gfm going to become part of the compiler?
†we also need to be specific about what flavor of markdown we want to adopt as the language standard. markdown parses differently if you assume it is commonmark, gfm, etc.
DocC doesn't do any special parsing of - Parameter(s) list items, especially not any validation against what appears in the symbol graph. Adding some kind of special handling for the each keyword would start to invite other questions about these list items in DocC, which we may not be prepared to answer. For example, we don't do anything special for inout parameters, attributes/macros that are applied to method parameters, or non-variadic type parameters at all. I admit i'm not familiar with the parameter packs proposal, but from a DocC implementor standpoint i'm weakly against adding special handling to these section callouts. It can be handled better in manual prose than anything we can do automatically.
(And, like @taylorswift just said, Swift-DocC isn't even the only game in town! If we standardize on DocC's behavior, we risk leaving those tools out.)
Interestingly enough, the compiler does do some Markdown parsing, for an XML rendering of comment structure in the IDE integration code. This solely uses swift-cmark, not Swift-Markdown, so while most Markdown structures can be handled, things like Asides are not, since those are handled solely in Swift-Markdown. This also means that:
This is already the case.
However, i feel like "writing an official standard for how doc comments are written" is out of scope for this thread, even if it does affect the proposal itself.
interesting. how come swift-markdown builds its own copy of cmark-gfm, when swift-syntax must dynamically link against the toolchain binaries? (or conversely, why doesn't swift-syntax do what swift-markdown does and duplicate the swift parser?)
DocC may not, but Xcode does: not comparing against the symbol graph, but identifying which part is the parameter name and which part is the description. If we want - Parameter each subview: one of many views to add to work, that has to be written down somewhere, right?
(I can’t remember at this moment if the Swift compiler checks that names match up with what’s in the declaration, but I would expect third-party tools like SwiftLint to do that if the compiler doesn’t.)
Could you expand a bit on the value of adding the each keyword to the markup syntax beyond conformity with the Swift language syntax? As you mentioned, documentation comments already use the internal parameter name so there doesn't seem to be a need for special-case here from an authoring perspective.
What Swift developers would intuitively write today is:
/// - Parameter variable: The list of variables to bind.
/// - Parameter input: The list of input values to bind each variable to.
func bind<each Input>(
variables variable: repeat Variable<each Input>,
to input: repeat each Input
)
Requiring the additional each results in a very similar syntax but with at least some added confusion on the author's part. They would have to learn a new documentation syntax to document these specific parameters.
/// - Parameter each variable: the list of variables to bind.
/// - Parameter each input: the list of input values to bind each variable to.
func bind<each Input>(
variables variable: repeat Variable<each Input>,
to input: repeat each Input
)
I definitely see value in rendering the actual parameter documentation in a different way – documentation engines like Swift-DocC should be provided enough information in the symbol graph to know which parameters are parameter packs and then identify them as such directly alongside the parameter's documentation. But I'm not sure I see the value in going the extra step of requiring the each in the actual authored prose.
Got it – that makes sense. I don't think I share this concern. From a user perspective, I think the parameter syntax is used to say "attach this description (Y) to this parameter (X)". If the description Y happens to line up grammatically with X – that's nice, but it's not a requirement. The documentation comment isn't meant to be read in isolation.
In other words, the syntax exists as a way to connect the dots between parameters and their descriptions, but then the full context of the parameter should be used to understand the description. I'm not reading:
/// - Parameter variable: The list of variables to bind.
in isolation. It's attached to the declaration where I can see that variable is a parameter pack. In that context, "a list of variables to bind" does match up with the parameter named variable.
That being said, I definitely see the need here for when the documentation is built and rendered to show these parameters in a special way. (Likely adding each).
To me the downside of introducing a new syntax here is pretty clear – it adds friction and confusion to documenting parameters. I don't think the rationale of it not matching the description is enough to overcome that – we should address that automatically with documentation tooling instead of adding an additional syntax for documentation writers to learn.