Generic trait auto distiguish

Hi, I saw ~ is used for ~const, so is there any plan to support something like the below piece of code?

struct Foo<T> {
  val: T,
}

impl<T: Copy> Foo<T> {
  fn foo(&self) {
    println!("copy");
  }
}

impl<T: ~Copy> Foo<T> {
  fn foo(&self) {
    println!("no copy");
  }
}

No, the ~const does not mean !const. Instead it’s an (unstable, not finalized) syntax used in trait bounds on const fn where something like

const fn foo<T: ~const Bar>(…) {…} 

means

  • when calling foo normally, you’ll need to ensure T: Bar
  • when calling foo in a const context (e.g. as an initializer to a static or in the definition of a const), you’ll have to ensure T: const Bar
    • note, that T: const Bar means that there’s not only an impl Bar for T but an impl const Bar for T, the latter containing all the same methods of Bar, but as const fns, instead of ordinary fns.

More information: Pre-RFC: Revamped const_trait_impl aka RFC 2632

So the ~ is not negation, instead it’s deliberately new (and, as mentioned, WIP/unstable/nonfinal) syntax with a very specific meaning.


The related question of whether something like

struct Foo<T> {
  val: T,
}

impl<T: Copy> Foo<T> {
  fn foo(&self) {
    println!("copy");
  }
}

impl<T: !Copy> Foo<T> {
  fn foo(&self) {
    println!("no copy");
  }
}

might ever work: answer is, yes probably at some point in the (possibly distant) future for certain traits and/or types negative trait bounds will be supported in rust; but not like this particular example for the trait Copy and generically over all types. The reason is: It’s currently an accepted change to add an implementation of Copy to a type over a minor semver-change. Anything that relies on T: !Copy would break over such a change. Of course, this particular example does not just have an impl based on T: !Copy, so it doesn’t fully break; changing behavior based on trait implementations is something that the WIP language feature “specialization” tackles – it does use different syntax and has lots of unresolved problems, but can essentially achieve the same thing.

2 Likes

~const as a trait bound modifier can be seen like this:

const fn foo<T: ~const Bar>(…) {…} 

is effectively:

constif(C) fn foo<constness C, T: constif(C) Bar>(…) {…} 

which expands to two functions with either constness C being const or not const:

const fn foo<T: const Bar>(…) {…} // use this one when called from const context
fn foo<T: Bar>(…) {…}  // use this one when called at runtime
1 Like

I think there's a couple of ways that this could happen. One interesting one would be for this to only match things for which there's an explicit impl<T> !Copy for Foo<T> {} using negative_impls - The Rust Unstable Book.

That would give three categories of things: things which are Copy now (and will be in the future unless there's a major version that breaks it), things where are promised that they won't be copy (unless there's a major version that breaks it), and things that haven't made a promise one way or the other yet (for which point neither of those impls would match).

5 Likes