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