# Pre-RFC: Revamped const\_trait\_impl aka RFC 2632

**URL:** <https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192>\
**Category:** language design\
**Created:** [August 18, 2021, 10:14am UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192 "2021-08-18T10:14:17Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![mbartlett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbartlett/32/8691_2.png) [@mbartlett](https://internals.rust-lang.org/u/mbartlett)\
**Post date:** [October 20, 2021, 1:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/41 "2021-10-20T13:59:27Z")

</div>

@U007D

It turns out that it was reverted due to breakage:

> <https://github.com/rust-lang/rust/issues/89432>
>
> I tried this code:
> 
> \`\`\`rust
> pub struct Datum {
> /// The name of this datu…m.
> pub name: String,
> 
> /// Whether the datum indicates support for the platform or not.
> pub pass: bool,
> 
> /// Short additional information to display to the user.
> pub info: Option\<String\>,
> 
> /// Longer explanatory message on how to resolve problems.
> pub mesg: Option\<String\>,
> }
> \`\`\`
> 
> \`\`\`rust
> fn dev\_kvm() -\> super::Datum {
> let dev\_kvm = std::path::Path::new("/dev/kvm");
> 
> super::Datum {
> name: "Driver".into(),
> pass: dev\_kvm.exists(),
> info: Some("/dev/kvm".into()),
> mesg: None,
> }
> }
> \`\`\`
> 
> I expected to see this happen:
> 
> Successful compilation. This has compiled and worked for years until \`nightly-2021-10-01\`. Reverting to \`nightly-2021-09-30\` produces a successful compilation.
> 
> Instead, this happened:
> 
> \`\`\`
> error\[E0277\]: the trait bound \`std::string::String: From\<&str\>\` is not satisfied
> --\> src/backend/kvm/mod.rs:23:24
> |
> 23 | name: "Driver".into(),
> | ^^^^ the trait \`From\<&str\>\` is not implemented for \`std::string::String\`
> |
> = note: required because of the requirements on the impl of \`Into\<std::string::String\>\` for \`&str\`
> help: consider introducing a \`where\` bound, but there might be an alternative better way to express this requirement
> |
> 19 | fn dev\_kvm() -\> super::Datum where std::string::String: From\<&str\> {
> | +++++++++++++++++++++++++++++++++++++
> 
> error\[E0277\]: the trait bound \`std::string::String: From\<&str\>\` is not satisfied
> --\> src/backend/kvm/mod.rs:25:20
> |
> 25 | info: Some("/dev/kvm".into()),
> | ---- ^^^^^^^^^^^^^^^^^ the trait \`From\<&str\>\` is not implemented for \`std::string::String\`
> | |
> | required by a bound introduced by this call
> |
> = note: required because of the requirements on the impl of \`Into\<std::string::String\>\` for \`&str\`
> help: consider introducing a \`where\` bound, but there might be an alternative better way to express this requirement
> |
> 19 | fn dev\_kvm() -\> super::Datum where std::string::String: From\<&str\> {
> | +++++++++++++++++++++++++++++++++++++
> \`\`\`
> 
> \### Meta
> \<!--
> If you're using the stable version of the compiler, you should also check if the
> bug also exists in the beta or nightly versions.
> \--\>
> 
> \`rustc --version --verbose\`:
> \`\`\`
> rustc 1.57.0-nightly (aa7aca3b9 2021-09-30)
> binary: rustc
> commit-hash: aa7aca3b954131720df725e70d12e902eb3be1de
> commit-date: 2021-09-30
> host: x86\_64-unknown-linux-gnu
> release: 1.57.0-nightly
> LLVM version: 13.0.0
> \`\`\`
> 
> cc @haraldh @wgwoods

> <https://github.com/rust-lang/rust/pull/89450>
>
> Should fix issue found in #89432

---

<div class="post-metadata">

**Author:** ![U007D](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/u007d/32/2172_2.png) [@U007D](https://internals.rust-lang.org/u/U007D)\
**Post date:** [October 23, 2021, 10:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/42 "2021-10-23T22:31:56Z")

</div>

👍

For the time being, the blanket impl won't propagate the constness of the `From` impl, so I'll just do an `impl const Into` for now. Thanks.

---

<div class="post-metadata">

**Author:** ![U007D](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/u007d/32/2172_2.png) [@U007D](https://internals.rust-lang.org/u/U007D)\
**Post date:** [January 8, 2022, 2:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/43 "2022-01-08T14:41:53Z")

</div>

> Syntax Change: We use `~const` instead of `?const` to signify the "const-if-const"ness. Please comment if you can come up with something better than `~const` , this is definitely up for bikeshed.

Is `~const` intended as placeholder syntax, to revert to either just `const` (which already serves to define both the const and non-const impls today) or `?const` (as "might be const" to be more explicit about the const-if-const aspect) before feature stabilization? (Unless I missed it, the Pre-RFC text doesn't appear to speak to this.)

Either might be reasonable interpretations of "const-if-const" (at least to my user's eye view) without adding a new sigil to the language, and I was wondering about the Pre-RFC authors' thoughts on this.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [January 8, 2022, 5:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/44 "2022-01-08T17:45:08Z")

</div>

I have wondered the same thing. I'm not thrilled by the idea of introducing yet another sigil that may confuse people new to Rust and that is hard to search for. `?const` (which looks similar to `?Sized`) would be more intuitive I believe.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [January 8, 2022, 5:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/45 "2022-01-08T17:59:58Z")

</div>

> [@Aloso](#):
>
> I'm not thrilled by the idea of introducing yet another sigil that may confuse people new to Rust and that is hard to search for.

Perhaps adding `~const` isn't that big of a problem.

To me `?Sized` keeps being confusing; possibly because it's _negative_, _taking away_ an assumption.

But `~const` is positive, _adding_ (conditionally) an assumption. It may end up being easy to grasp.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [January 8, 2022, 9:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/46 "2022-01-08T21:08:41Z")

</div>

> [@Aloso](#):
>
> `?const` (which looks similar to `?Sized` ) would be more intuitive I believe.

But isn't its meaning different than `?Sized`? Looking at this without prior knowledge of the problem I would expect `const` to be the default just like `Sized` is the default and `?const` being the opt-out, which is definitely not the case.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [January 8, 2022, 9:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/47 "2022-01-08T21:58:03Z")

</div>

I read `?Sized` as "maybe sized". Likewise, `?const` means "maybe const".

I understand that `const` being opt-in while `Sized` is (usually) opt-out is an inconsistency. But I don't see it as a problem for understanding what `?const` means, because the inconsistency only relates to the default behavior when the trait bound/modifier is _absent_.

---

<div class="post-metadata">

**Author:** ![fee1-dead](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fee1-dead/32/8232_2.png) [@fee1-dead](https://internals.rust-lang.org/u/fee1-dead)\
**Post date:** [January 11, 2022, 6:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/48 "2022-01-11T18:11:52Z")

</div>

Another difference between `?Sized` and `~const` is that `?Sized` means you explicitly allow DST to be used, so it is more like "I don't care about the sized-ness of this type".

..while `~const` is not "I don't care about the constness of the trait implementation" but rather "constness depends on whether you want to use this in const contexts".

> [@Aloso](#):
>
> the inconsistency only relates to the default behavior when the trait bound/modifier is _absent_ .

When you add a prefix to something, I'd expect it to do the same thing to the thing that it applies to, regardless of what the thing actually is.

Adding `?Sized` _relaxes_ a bound, whereas `~const` makes a bound _stricter_. Adding the former is not a breaking change, but adding the latter is.

---

<div class="post-metadata">

**Author:** ![asv](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/asv/32/8948_2.png) [@asv](https://internals.rust-lang.org/u/asv)\
**Post date:** [January 12, 2022, 11:34am UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/49 "2022-01-12T11:34:31Z")

</div>

> [@fee1-dead](#):
>
> whereas `~const` makes a bound _stricter_

If so, why not use const? Without any sigils.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [January 12, 2022, 2:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/50 "2022-01-12T14:36:57Z")

</div>

> [@asv](#):
>
> If so, why not use const? Without any sigils.

- `const` would mean the generic parameter always has to be `const`
- `~const` is suggested to mean a `const` bound that gets "activated"  
only when the `fn` is used in a `const` context

What is your view? Is this easy to learn? Difficult? Easier that `?Sized`? Intuitive?

---

<div class="post-metadata">

**Author:** ![asv](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/asv/32/8948_2.png) [@asv](https://internals.rust-lang.org/u/asv)\
**Post date:** [January 12, 2022, 4:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/51 "2022-01-12T16:23:57Z")

</div>

`~const` means that generic type maybe const, maybe not? If yes - `?const` looks more intuitive for me. Reads like maybe const.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [January 12, 2022, 5:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/52 "2022-01-12T17:01:44Z")

</div>

The hope behind suggesting `~` was to emphasize the fundamental difference

- `?Sized` - "do not dare to assume the type is `Sized`, shish!"
- `~const` - "do assume it's `const` if you're called in a `const` context"

How would you assess intuitiveness and learnability here?..

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [January 12, 2022, 6:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/53 "2022-01-12T18:30:51Z")

</div>

There are plenty of ways of _reading_ `?Sized` in ways that sync with the meaning of `?const`. I read it as "possibly `Unsized`" which is even less sensical. Viewing prefix `?` as an operator currently its meaning is clear:

> All type parameters have an implicit bound of `Sized` . The special syntax `?Sized` can be used to remove this bound if it’s not appropriate. [`T + ?Sized` actually means `T + Sized + ?Sized` or just plain `T`]

So to use `?` here it should be the case that all type parameters are implicitly `T + const`. Thus `T + ?const` actually means `T + const + ?const` i.e. `T`. But that's not true or intended to be true.

I don't know if this definition as an operator is useful going forward, it's currently unique syntax. Hopefully Rust doesn't accrue too many new implicit default bounds.

I can certainly imagine changing this syntax to just mean "maybe whatever", in which case `?Sized` and `?const` and `?async` all make sense, with unique meanings for what new constraints those imply.

---

<div class="post-metadata">

**Author:** ![Rust.er](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rust.er/32/9618_2.png) [@Rust.er](https://internals.rust-lang.org/u/Rust.er)\
**Post date:** [January 12, 2022, 8:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/54 "2022-01-12T20:01:17Z")

</div>

`~` and `?` here definitely has subtle difference. `?Sized` means maybe Sized / Option\<`Sized`\>, but `~const` means `conditional const` -- "const if in const context".

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [January 13, 2022, 11:15am UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/55 "2022-01-13T11:15:13Z")

</div>

> [@atagunov](#):
>
> - `?Sized` - "do not dare to assume the type is `Sized` , shish!"
> - `~const` - "do assume it's `const` if you're called in a `const` context"
> 
> How would you assess intuitiveness and learnability here?..

From personal experience, it took me _quite_ a while to understand the reasoning behind `~const`, and even now I'm not 100% sure I fully do. From a newcomer's perspective, I think the first questions would be "what exactly is a 'const context'?", and "if something **can** be const, why not make it const always?"

But aside from this, my main issue with `~const` is that I see it ending up _everywhere_: if you can mark something as `~const`, why wouldn't you? Together with these observations:

> [@RalfJung](#):
>
> I think I would prefer a syntax like `impl<T: ~const Add> ~const Add for MyType<T>` .
> 
> [...]
> 
> On the other hand, for consistency we should then probably also write `~const fn foo<T: ~const Add>` . Not sure how I feel about that.

... this could end up in a blog post _"Rust: `~const` **ALL** the things!"_ 😉

---

<div class="post-metadata">

**Author:** ![SlightlyOutOfPhase](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/slightlyoutofphase/32/5440_2.png) [@SlightlyOutOfPhase](https://internals.rust-lang.org/u/SlightlyOutOfPhase)\
**Post date:** [January 13, 2022, 4:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/56 "2022-01-13T16:26:32Z")

</div>

> [@fee1-dead](#):
>
> Adding the former is not a breaking change, but adding the latter is.

Well, that's only true if the function / method in question was _already_ a `const fn`. Adding `~const` in the process of turning something _into_ a `const fn` can't cause breakage, because the only possible existing calls are guaranteed to be runtime ones on which the `~const` bounds won't have any impact.

---

<div class="post-metadata">

**Author:** ![anon32976453](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@anon32976453](https://internals.rust-lang.org/u/anon32976453)\
**Post date:** [January 13, 2022, 9:48pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/57 "2022-01-13T21:48:06Z")

</div>

The accumulation of all these subtle distinctions adds a lot of redundant complexity to Rust and points to a core design problem with the current model imo.

Const shouldn't affect the semantics of a function `foo` at all. Its behaviour ought to be the same. By using const the programmer actually wanted to change when it was executed or i.o.w **how it was called**. Hence, a much simpler and more orthogonal design ought to aim to mark call sites, not function definitions.

There are a few challenges for such an approach for the compiler writers, but non that can't be overcome imo.

- The restrictions on what can be done at compile time should be removed. It's just regular rust code simply executed at an earlier stage. Doing I/O and calling external creates are really a question of what is the API exposed by the interpreter, not a fundamental semantic difference.
- Security (and build reproducibility) is similarly a question of isolating the execution of the interpreter and not a fundamental semantic difference either.

Warm + wasi are an awesome pre-existing set of technologies with native rust implementations that can be used to address the second point in particular.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [January 15, 2022, 12:06am UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/58 "2022-01-15T00:06:23Z")

</div>

Sorry for being slow.. aren't the call sites already marked?  
It's pretty clear when an `fn` is called in a `const` context?..

---

<div class="post-metadata">

**Author:** ![anon32976453](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@anon32976453](https://internals.rust-lang.org/u/anon32976453)\
**Post date:** [January 15, 2022, 4:02am UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/59 "2022-01-15T04:02:00Z")

</div>

That's right. Const call sites are already marked.

I was making the complementary point that marking function definitions as const should be removed.

The current model tries to paper over the issues of cross compilation but by doing so it essentially forces conditional compilation style issues on everyone. The most fundamental tool of abstraction in Rust is the trait system. By restricting functions and traits/impls to be some checked subset of Rust everything beyond a simple function needs to reason about this subset.

This is a clear inversion of the Pareto principle (80/20 rule). I rather if I need to be extra careful with my reasoning in the **few** instances when I use platform dependent code in a cross compilation scenario where executing say `size_of<T>` can change the result, than to need to reason about `~const` bounds everytime I need a generic function to call a trait method.

In other words, this is another instance of an XY problem.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [January 15, 2022, 2:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192/60 "2022-01-15T14:49:55Z")

</div>

> [@anon32976453](#):
>
> The restrictions on what can be done at compile time should be removed. It's just regular rust code simply executed at an earlier stage. Doing I/O and calling external creates are really a question of what is the API exposed by the interpreter, not a fundamental semantic difference.

We need determinism for a sound type system. Otherwise `[u8; foo()]` be assignable `[1, 2, 3]` according to the typechecker as `foo()` evaluates to 3, but then during codegen it may evaluate to say 100, thus exposing uninitialized memory.

Another thing is that we need to know what memory we need to include into the executable and where there are relocations. This is impossible to get unless the code is instrumented to give this information. This instrumentation is pretty much exactly as restrictive as the const eval engine as OS libraries can't be instrumented and this instrumentation can't support pointer to integer casts.

> [@anon32976453](#):
>
> Security (and build reproducibility) is similarly a question of isolating the execution of the interpreter and not a fundamental semantic difference either.

Build reproducibility wouldn't be possible when allowing calls into external libraries without disabling ASLR, clearing the `AT_RANDOM` auxiliary value (which is random) and a whole lot of other things. Not all platforms support disabling ASLR in the first place for security reasons.

[Previous page](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192.md?page=2)

[Next page](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192.md?page=4)
