This proposal specifies how unused pattern bindings are written in the Carbon programming language. This is a more general problem statement of "how do users specify unused function parameters" as function parameter declarations are a more specific form of pattern.
Related issue: #1996.
"How does a user of Carbon declare an unused pattern binding?"
Given that function parameters are a specific type of pattern binding, a more specific question that will have the same answer is "How does a user of Carbon declare an unused function parameter?"
Bindings that can be specified as unused makes code explicit and unambiguous. Authors of code can clearly state that a value is not intended to be used. Tools such as compilers or linters can explicitly handle a parameter that is specified as unused, but later used, or a parameter that is unused despite not being specified as unused.
See
the overall design
for the current state of things with regards to name bindings and the underscore
character, _.
See issue #476: Optional argument names (unused arguments) for the previous conversation on this topic.
Note: These are not exhaustive lists and not intended to be thoroughly investigated, rather a brief overview of some prior art.
C and C++ style guides, linters, and other tools have addressed unused function parameters specifically with varying levels of clarity for readers.
maybe_unused attributeunused attributeMore generally, various languages use the underscore character (_) to signal
an unused binding or pattern.
_ Patterns_, ignored_, or unused_ to be unused_ CasesUsers can explicitly declare a value in a pattern as unused in two forms:
_: i32 : Using the underscore token, _, in place of a name.
unused size: i32 : Using the leading unused keyword followed by the
name.
Introducing two syntaxes satisfies the desire to have a terse way to discard values, but still provides authors with a more verbose, explicit syntax that preserves the name.
Both approaches are unambiguous -- to human readers and authors as well as
programmatic interpretations. The inclusion of an explicit unused keyword
allows authors to preserve the name of a value for documentation purposes, while
still explicitly marking the value as discarded in an interpretable way to
humans and programs alike.
The unused keyword would be a new keyword in Carbon. This keyword would only
be valid when preceding a name in a pattern binding and the keyword would
tightly bind to the following name, disallowing specifying an entire sub-pattern
as unused.
unused name bindingsNames that are qualified with the unused keyword are visible for name lookup
but uses are invalid, including when they cause ambiguous name lookup errors. If
attempted to be used, a compiler error will be shown to the user, instructing
them to either remove the unused qualifier or remove the use.
The inverse, where a name is not qualified by the unused qualifier, but never
used, will cause the compiler to emit a warning diagnostic, informing the user
that a given name was not used and suggesting to either remove the binding or
mark it as unused.
Examples with an unused function parameter
// Function declaration (may be in API file)
fn Sum(x: List(i32), size: i32) -> i32;
// Implementation that doesn't use the size parameter
fn Sum(x: List(i32), _: i32) -> i32 { ... }
// or:
fn Sum(x: List(i32), unused size: i32) -> i32 { ... }
Examples with an unused variable
fn Bar() -> (i32, i32);
fn Foo() -> i32 {
var (x: i32, _: i32) = Bar();
// or:
var (x: i32, unused y: i32) = Bar();
return x;
}
Examples with an unused case binding
fn Bar() -> (i32, i32);
fn Foo() -> i32 {
match (Bar()) {
case (42, y: i32) => {
return y;
}
case (x: i32, _: i32) => {
return x;
}
// or:
case (x: i32, unused y: i32) => {
return x;
}
}
}
This proposal uses the underscore, _, character to denote an unused value, a
meaning used across various other programming languages. A lone underscore
character only has a single meaning in Carbon and will be unambiguous across
contexts.
Both syntaxes are easily read by humans, either by seeing the _ character
alone, or by introducing a keyword that allows code to read naturally such as
unused size : i32.
The inclusion of two syntaxes allows authors to decide when they will favor conciseness or explicitness.
C++ allows function parameters to be unnamed, allowing function declarations such as
int Foo(int) { ... }
int Foo(int /*unused_name*/) { ... }
Advantages:
Disadvantages:
/* */ comments, so this option is
effectively a non-starter_Carbon could provide only a single way to discard a value with the underscore,
_, token
// Function declaration (may be in API file)
fn Sum(x: List(i32), size: i32) -> i32;
// Implementation that doesn't use the size parameter
fn Sum(x: List(i32), _: i32) -> i32 { ... }
Advantages:
Disadvantages:
_Carbon could treat identifiers prefixed with _ as unused identifiers and
discard their names.
// Function declaration (may be in API file)
fn Sum(x: List(i32), size: i32) -> i32;
// Implementation that doesn't use the size parameter
fn Sum(x: List(i32), _size: i32) -> i32 { ... }
Advantages:
Disadvantages:
_ character), even while it remains an
identifier seems more subtle and indirect than necessary.
A potential syntax for naming unused bindings while retaining the underscore,
_, token is an optional name suffix following the underscore token.
// Function declaration (may be in API file)
fn Sum(x: List(i32), size: i32) -> i32;
// Implementation that doesn't use the size parameter
fn Sum(x: List(i32), _ size: i32) -> i32 { ... }
Advantages:
Disadvantages:
unusedWhile attributes aren't designed yet, there's a possibility that in the future,
the Carbon language will have some mechanism to attach metadata to parts of
source code to inform readers, compilers, and other tools. Its conceivable that
there could be an unused attribute which could be use to implement similar
semantics as the proposed unused keyword.
Advantages:
Disadvantages:
unused bindings specify unambiguous,
absolute behavior for the compiler's handling of names, similar to the
private keyword, using attributes as the transport for this semantic
information is indirect.Given that attributes are not designed and may go in a number of unknown directions, it might be worth revisiting this option once attributes are fully designed.