# Unused Pattern Bindings (Unused Function Parameters)

<!--
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Exceptions. See /LICENSE for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->

[Pull request](https://github.com/carbon-language/carbon-lang/pull/2022

<!-- toc -->

## Table of contents

-   [Abstract](#abstract)
-   [Problem](#problem)
-   [Background](#background)
-   [Proposal](#proposal)
-   [Details](#details)
    -   [The behavior of `unused` name bindings](#the-behavior-of-unused-name-bindings)
    -   [Examples](#examples)
-   [Rationale](#rationale)
-   [Alternatives considered](#alternatives-considered)
    -   [Commented names](#commented-names)
    -   [Only short form support with `_`](#only-short-form-support-with-_)
    -   [Named identifiers prefixed with `_`](#named-identifiers-prefixed-with-_)
    -   [Anonymous, named identifiers](#anonymous-named-identifiers)
    -   [Attributes](#attributes)

<!-- tocstop -->

## Abstract

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](https://github.com/carbon-language/carbon-lang/issues/1996).

## Problem

"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.

## Background

See
[the overall design](https://github.com/carbon-language/carbon-lang/blob/09e4417431b77c05ceb2a98dd38833276514a1ff/docs/design/README.md#binding-patterns)
for the current state of things with regards to name bindings and the underscore
character, `_`.

See
[issue #476: Optional argument names (unused arguments)](https://github.com/carbon-language/carbon-lang/issues/476)
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.

-   [Standard C++ Foundation's guidelines on unused parameters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-unused)
-   [Google's C++ style guide recommendations on unused parameters](https://google.github.io/styleguide/cppguide.html#Function_Declarations_and_Definitions)
-   [C++ `maybe_unused` attribute](https://en.cppreference.com/w/cpp/language/attributes/maybe_unused)
-   [GCC C `unused` attribute](https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html#index-g_t_0040code_007bunused_007d-attribute_002e-2640)

More generally, various languages use the underscore character (`_`) to signal
an unused binding or pattern.

-   [Rust `_` Patterns](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#ignoring-values-in-a-pattern)
-   [Golang Blank Identifiers](https://go.dev/ref/spec#Blank_identifier)
-   [PyLint allows parameters starting with `_`, `ignored_`, or `unused_` to be unused](https://pylint.pycqa.org/en/latest/user_guide/configuration/all-options.html#ignored-argument-names)
-   [Scala Wildcard Patterns](https://www.scala-lang.org/files/archive/spec/2.11/10-pattern-matching.html#variable-patterns)
-   [Crystal `_` Cases](https://crystal-lang.org/reference/1.5/syntax_and_semantics/case.html#underscore-allowed)

## Proposal

Users 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.

## Details

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`.

### The behavior of `unused` name bindings

Names 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

Examples with an unused function parameter

```carbon
// 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

```carbon
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

```carbon
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;
    }
  }
}
```

## Rationale

-   This proposal supports the Carbon goal of having
    [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
    -   Carbon should not use symbols that are difficult to type, see, or
        differentiate from similar symbols in commonly used contexts.
    -   Syntax should be easily parsed and scanned by any human in any
        development environment, not just a machine or a human aided by semantic
        hints from an IDE.
    -   Explicitness must be balanced against conciseness, as verbosity and
        ceremony add cognitive overhead for the reader, while explicitness
        reduces the amount of outside context the reader must have or assume.

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.

## Alternatives considered

### Commented names

C++ allows function parameters to be unnamed, allowing function declarations
such as

```
int Foo(int) { ... }
int Foo(int /*unused_name*/) { ... }
```

Advantages:

-   Consistency with C++

Disadvantages:

-   Carbon does not intend to support `/* */` comments, so this option is
    effectively a non-starter

### Only short form support with `_`

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:

-   A smaller language, one less keyword, and a single way to write code

Disadvantages:

-   Less expressiveness, less documentation through names

### Named identifiers prefixed with `_`

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:

-   Reuse of the underscore character in both short and long form bindings
-   Functionally similar to commented names in C++

Disadvantages:

-   Tying the semantics of a name being unused to the particular spelling of the
    identifier (starting with a `_` character), even while it remains an
    identifier seems more subtle and indirect than necessary.
    -   We shouldn't use identifier spellings as a side-channel for semantic
        information.
    -   Semantics, including used versus unused, should be conveyed in an
        orthogonal manner to the name rather than tying them together.
-   Would require the name to change when shifting between being used or unused,
    which could undermine some of its utility such as remaining for annotations,
    metaprogramming, or diagnostics.

### Anonymous, named identifiers

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:

-   Reuse of the underscore token in both short and long form bindings

Disadvantages:

-   The underscore token, while consistent, may be less human readable than a
    dedicated keyword such as `unused`

### Attributes

While 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:

-   Opens the inspection and subsequent actions taken to whatever ecosystem and
    programmatic support is introduced by attributes.
-   Solves a specific problem with a generic approach
    -   Removes the introduction of a new keyword

Disadvantages:

-   Given the current proposal where `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.
