This feature introduces a special identifier that may only be assigned. It is breaking, but only in a small way: _ is no longer a valid variable reference.
The blank identifier_ (a single underscore, U+005F LOW LINE) is a special identifier that may only be assigned and may never be referenced. Assigning a value to it can still generate compiler output, for example if evaluating the assigned value produces side-effects. The point of having a blank identifier is to pacify static analysis errors.
TLDR: We can assign a value to _ but we can never reference it in an expression.
let _: str = "unused";
_; % error
Motivational background. We’ll try to send a callback function into the forEach list method. Recall that forEach takes a function of type (T, int, T[]) => void as its argument. Our callback will only read the second parameter (the index).
linter error: parameters item and source are unused
Static analysis will complain about our callback because it doesn’t reference the item and source parameters. We can remove the source parameter (because a function of type (T, int) => void is assignable to type (T, int, T[]) => void), but we can’t remove the item parameter because that would change the order.
Here, the blank identifier is treated more as a keyword than as an expression.
As a pseudo-keyword, the blank identifier can be assigned multiple times, without encountering duplicate declaration errors. Only the expressions are evaluated; no pointers are actually created.
List.<str>(["apple", "banana", "cherry"]).forEach.((_: str, index: int, _: str[]): void { % no error
print.(index);
});
let (_, _, c, d): str[4] = ["a", "b", "c", "d"]; % no error
(Recall that normal variables would not allow that — e.g., let (x, x): str[2] = ["a", "b"]; would be an assignment error.)
The blank identifier is a valid record key since record keys may be any word including reserved keywords. However, as a valid key, it may not be declared multiple times.
This feature introduces a special identifier that may only be assigned. It is breaking, but only in a small way:
_
is no longer a valid variable reference.The blank identifier
_
(a single underscore, U+005F LOW LINE) is a special identifier that may only be assigned and may never be referenced. Assigning a value to it can still generate compiler output, for example if evaluating the assigned value produces side-effects. The point of having a blank identifier is to pacify static analysis errors.TLDR: We can assign a value to
_
but we can never reference it in an expression.Motivational background. We’ll try to send a callback function into the
forEach
list method. Recall thatforEach
takes a function of type(T, int, T[]) => void
as its argument. Our callback will only read the second parameter (the index).Static analysis will complain about our callback because it doesn’t reference the
item
andsource
parameters. We can remove thesource
parameter (because a function of type(T, int) => void
is assignable to type(T, int, T[]) => void
), but we can’t remove theitem
parameter because that would change the order.So the solution here is to declare a special parameter, the blank identifier
_
, as a placeholder for the unused parameter.This passes static analysis, and because the blank identifier can never be referenced, the linter doesn’t expect it to be used.
The same principle applies to destructuring variables:
Here, the blank identifier is treated more as a keyword than as an expression.
As a pseudo-keyword, the blank identifier can be assigned multiple times, without encountering duplicate declaration errors. Only the expressions are evaluated; no pointers are actually created.
(Recall that normal variables would not allow that — e.g.,
let (x, x): str[2] = ["a", "b"];
would be an assignment error.)The blank identifier is a valid record key since record keys may be any word including reserved keywords. However, as a valid key, it may not be declared multiple times.
The same applies to function arguments. We may assign an expression to a named argument, but not more than once.
Note that even though we can send
_= "apple"
as a valid function argument, the function never references it!