Skip to content

Commit be40ba7

Browse files
committed
Wildcard identifiers in constants
1 parent 352abc0 commit be40ba7

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

text/0000-const-wildcard.md

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
- Feature Name: `const_wildcard`
2+
- Start Date: 2018-08-18
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Allow assigning constants to `_`, as in `const _: TYPE = VALUE`, analogous to
10+
`let _ = VALUE`.
11+
12+
# Motivation
13+
[motivation]: #motivation
14+
15+
The ability to ensure that code type checks while discarding the result is
16+
useful, especially in custom derives. For example, the following code will not
17+
compile if the type `MyType` doesn't implement the trait `MyTrait`:
18+
19+
```rust
20+
const _FOO: () = {
21+
use std::marker::PhantomData;
22+
struct ImpelementsMyTrait<T: MyTrait>(PhantomData<T>);
23+
let _ = ImplementsMyTrait::<MyType>(PhantomData); // type checking error if MyType: !MyTrait
24+
()
25+
};
26+
```
27+
28+
Unfortunately, this requires coming up with a unique identifier to assign to.
29+
This is error-prone because no matter what identifier is chosen, there's always
30+
a possibility that a user will have already used the same identifier in their
31+
code. If writing `const _: () = { ... }` were valid, then this would be a
32+
non-issue - the `const _` could be repeated many times without conflicting with
33+
any other identifier in scope.
34+
35+
# Guide-level explanation
36+
[guide-level-explanation]: #guide-level-explanation
37+
38+
Allow assigning to `_` when defining a new constant. Just like `let _`, this
39+
doesn't introduce any new bindings, but still evaluates the rvalue at compile
40+
time like any other constant.
41+
42+
# Reference-level explanation
43+
[reference-level-explanation]: #reference-level-explanation
44+
45+
The following changes are made to the language:
46+
47+
## Grammar
48+
49+
The grammar of `item_const` is changed from:
50+
51+
```text
52+
item_const : CONST ident ':' ty '=' expr ';' ;
53+
```
54+
55+
to:
56+
57+
```text
58+
item_const : CONST (ident | UNDERSCORE) ':' ty '=' expr ';' ;
59+
```
60+
61+
## Type checking
62+
63+
When type checking an associated `const` item, the token `_` may not occur as
64+
the name of the item.
65+
66+
When type checking a `const` item not inside an `impl` item, the token `_` is
67+
permitted as the name of such an item. When that token does occur, it is
68+
replaced with a freshly generated and unique identifier.
69+
70+
# Drawbacks
71+
[drawbacks]: #drawbacks
72+
73+
The rules around constant identifiers are made somewhat more complicated, as is
74+
the compiler logic for handling them. A distinction is introduced between
75+
associated `const` items (inside `impl`s) and non-associated `const` items.
76+
77+
# Rationale and alternatives
78+
[alternatives]: #alternatives
79+
80+
## Rationale
81+
82+
This would allow more ergonomic uses of a number of patterns used today:
83+
- Ensuring that types have certain trait bounds in custom derives, as explained
84+
in the [Motivation] section.
85+
- [`const_assert!`](https://docs.rs/static_assertions/0.2.5/static_assertions/macro.const_assert.html)
86+
and other macros in the
87+
[`static_assertions`](https://docs.rs/static_assertions/0.2.5/static_assertions/index.html)
88+
crate, which currently work only in a scope (so that they can use a `let`
89+
binding) or requires the user to specify a scope-unique name for a function
90+
which will be used to contain the expression that is the meat of the macro.
91+
92+
Eventually, we will likely want to support fully general pattern matching just
93+
like in `let` bindings (e.g., `const (a, b): (u8, u8) = (1, 1)`) to not have
94+
`const _` be a special case in the language. However, this RFC leaves the
95+
details of such a design up to a future RFC.
96+
97+
## Alternatives
98+
99+
- We could provide procedural macros with an API that fetches a new,
100+
globally-unique identifier.
101+
- We could support anonymous modules (`mod { ... }` or `mod _ { ... }`).
102+
103+
# Prior art
104+
[prior-art]: #prior-art
105+
106+
Go allows unnamed constants using the syntax `const _ = ...`. It also allows
107+
top-level variable bindings which are evaluated at init time, before `main` is
108+
run - `var _ = ...`. This latter syntax is often used to ensure that a
109+
particular type implements a particular interface, as in this example [from the
110+
standard library](https://golang.org/src/math/big/ftoa.go#L379):
111+
112+
```go
113+
var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
114+
```
115+
116+
# Unresolved questions
117+
[unresolved]: #unresolved-questions
118+
119+
None.

0 commit comments

Comments
 (0)