{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreibleswaesxuwri7zhwcmt3cpww2lr2jmopv4sh4febyjacm2tlste",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mnkqi27ztg42"
  },
  "path": "/t/named-impl-with-implementation-selection-variant/24374#post_1",
  "publishedAt": "2026-06-05T17:17:42.000Z",
  "site": "https://internals.rust-lang.org",
  "tags": [
    "negative-impls",
    "[Pre-RFC] Selectable Trait Implementations",
    "[Pre-RFC] Scoped `impl Trait for Type`",
    "Looking for RFC coauthors on \"named impls\"",
    "Named impls and impl generics"
  ],
  "textContent": "# Rust named impl Draft\n\nThe purpose is clear: to bypass Rust's orphan rule.\nThe proposed syntax should be more fluent to write, more natural to read, and more complete than the referenced proposals.\n\n  1. Introduce named trait implementations (named-impl)\n\n\n\n\n    pub impl<T> Trait1 for Struct1<T> use ST1 {\n        fn trait1_fn(&self) {\n            println!(\"named impl ST1\");\n        }\n    }\n\n\n  2. Introduce a new type definition syntax, the Implementation Selection Variant (Impl Variant for short)\n\n\n\n\n    type Struct1Default = Struct1<i32> + _ use default;\n    type Struct1WithST1 = Struct1<i32> + Trait1 use ST1;\n\n\n## Overview\n\n\n    // Default impl for struct and trait, same as Rust 2024 edition\n    pub struct Struct1<T>(T);\n    pub trait Trait1 {\n        fn trait1_fn(&self);\n    }\n    impl<T> Trait1 for Struct1<T> {\n        fn trait1_fn(&self) {\n            println!(\"default impl\");\n        }\n    }\n\n    // New named-impl definition, can be defined in any crate\n    // ST1 below lives in the Type Namespace\n    pub impl<T> Trait1 for Struct1<T> use ST1 {\n        fn trait1_fn(&self) {\n            println!(\"named impl ST1\");\n        }\n    }\n\n    // Forbidden: using `default` as a named-impl name\n    pub impl Clone for i32 use default {} // ❌\n\n    // Import with `use` just like structs and traits; the full path mod1::ST1 can also be used\n    use mod1::{Struct1, Trait1, ST1};\n\n    // Type definitions\n    type Struct1Generic = Struct1<i32>;\n    // A generic type, which by default resolves to the following line: Struct1<i32> + _ use default\n\n    type Struct1Default = Struct1<i32> + _ use default;\n    // A concrete type, behaving exactly like Struct1 in Rust 2024; no named-impl is used.\n    // `default` is a weak keyword here.\n\n    type Struct1WithST1 = Struct1<i32> + Trait1 use ST1;\n    // A concrete type, same layout as Struct1, but uses ST1's implementation for Trait1.\n    // The trailing `_ use default` is implicitly omitted.\n\n    // Different impl => different types\n    assert!(TypeId::of::<Struct1Default>() != TypeId::of::<Struct1WithST1>());\n\n    // Complex definition 1\n    type ComplexType1 = &(i32 + Trait1 use ST1) + Trait2 use ST2;\n\n    // Complex definition 2: overlapping implementations and priority rules\n    type ComplexType2 = Struct1<i64>\n        + From<i32> use mod2::Struct1Fromi32\n        + From<_: Add> use default\n        + From<_> use StructFrom\n        + Trait1 use ST1;\n    // Multiple named-impl generic parameters; overlapping of traits is allowed.\n    // When acting as From<i32>, Struct1Fromi32 is used; as From<&str>, StructFrom is used.\n    // The first matching trait (before `use`) from left to right wins and its implementation is used.\n\n\n    // Type conversions\n    let s = Struct1(1); // defaults to Struct1<i32> + _ use default\n    let mut s_ref_named: &(Struct1<i32> + Trait1 use ST1) = &s; // ✅ type conversion\n    let s_ref_default = s_ref_named as &(Struct1<i32> + _ use default); // ✅ mutual conversion\n    s_ref_named = s_ref_default; // ❌ implicit conversion without explicit type annotation is forbidden\n\n    let s4 = Struct1(4); // defaults to Struct1<i32> + _ use default\n    let s5: Struct1<i32> + Trait1 use ST1 = s4; // move plus type conversion\n\n    let vs: Vec<Struct1<i32>> = vec![]; // defaults to Vec<Struct1<i32> + _ use default>\n    let vs1: &Vec<Struct1<i32> + Trait1 use ST1> = &vs; // Struct1 with impl variant can appear anywhere in the type\n    let vs2: &Vec<Struct1<i32> + _ use default> = vs1;\n\n\n    // End usage\n    // Any T: Trait1 can be instantiated with both Struct1<i32> + _ use default and Struct1<i32> + Trait1 use ST1\n\n    // 1. Direct call\n    s5.trait1_fn();\n\n    // 2. UFCS\n    <Struct1<i32> as Trait1 use ST1>::trait1_fn(&s5);\n\n    // 3. Generic function\n    fn use_trait1<T: Trait1>(a: &T) {\n        a.trait1_fn();\n    }\n\n    use_trait1(s_ref_default); // default impl\n    use_trait1(s_ref_named); // named impl ST1\n\n    // 4. Generic type\n    pub struct Struct2<'a, T: Trait1>(&'a T);\n    impl Struct2<'a, T: Trait1> {\n        pub fn use_inner(&self) {\n            self.0.trait1_fn();\n        }\n    }\n\n    let s21 = Struct2(s_ref_default);\n    s21.use_inner(); //  default impl\n\n    let s22 = Struct2(s_ref_named);\n    s22.use_inner(); // named impl ST1\n\n\n    // trait object\n    let mut dyn_trait1: &dyn Trait1;\n\n    dyn_trait1 = s_ref_named;\n    dyn_trait1.use_inner(); // named impl ST1\n\n    dyn_trait1 = s_ref_default;\n    dyn_trait1.use_inner(); //  default impl\n\n\n    // impl trait\n    // 1. `impl trait` in argument position is merely syntactic sugar for generics\n    fn use_trait1(a: &impl Trait1) {\n        a.trait1_fn();\n    }\n    use_trait1(s_ref_default); // default impl\n    use_trait1(s_ref_named); // named impl ST1\n\n    // 2. `impl trait` in return position\n    fn return_trait1() -> impl Trait1 {\n        let s4 = Struct1(4); // defaults to Struct1<i32> + _ use default\n        return s4 as (Struct1<i32> + Trait1 use ST1); // move plus type conversion\n    }\n\n\n\n## Prohibition Rules\n\n  1. Named-impl must be forbidden for `Copy`, `Drop`, `Send`, `Sync`, `Unpin`, etc.\n\n\n\n\n    #[disable_named_impl(all)]\n    pub trait Copy {}\n\n\n`#[disable_named_impl(all)]` can be used by external code and placed on traits, structs, enums, etc.\n\n  2. Named-impl must be forbidden for `Hash`, `Ord`, `PartialOrd`, `Eq`, `PartialEq`, etc. at least when a default implementation exists.\n\n\n\n\n    #[disable_named_impl(exist_default)]\n    pub trait Hash {}\n\n\n`#[disable_named_impl(exist_default)]` can be used by external code and placed on traits, structs, enums, etc.\n\n## Extended Usages\n\n  1. Implementing external traits for external types, bypassing the orphan rule.\n\n  2. Compile-time proxy, or function decorator\n(akin to `java.lang.reflect.Proxy` or Python decorators)\n\n\n\n\n\n    impl fmt::Display for i32 use ProxyDisplay {\n        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n            write!(f, \"before \")?;\n            (self as &(i32 + Display use default)).fmt(f)?;\n            write!(f, \" after\")?;\n            Ok(())\n        }\n    }\n\n    // Generic proxy, but might be impossible to write due to recursion\n    impl<T: Display> fmt::Display for T use ProxyDisplayDefault {\n        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n            write!(f, \"before \")?;\n            (self as &(T + Display use default)).fmt(f)?; // ❓\n            write!(f, \" after\")?;\n            Ok(())\n        }\n    }\n\n\n  3. Specialization, partial specialization\n\n\n\n\n    // Overlapping implementations and priority rules\n    type ComplexType2 = Struct1<i64>\n        + From<i32> use mod2::Struct1Fromi32\n        + From<_: Add> use default\n        + From<_> use StructFrom\n        + Trait1 use ST1;\n    // Multiple named-impl generic parameters; overlapping of traits is allowed.\n    // When acting as From<i32>, Struct1Fromi32 is used; as From<&str>, StructFrom is used.\n    // The first matching trait (before `use`) from left to right wins.\n\n\n## Implicit Type Generics, Optional\n\n  1. Generic bounds can be structs or enums\n\n\n\n\n    #[derive(Default)]\n    struct Struct1;\n    impl Trait1 for Struct1 {};\n    impl Trait1 for Struct1 use TS1 {};\n    fn use_struct1<T: Struct1>() {\n        T::default().trait1_fn();\n    }\n\n    use_struct1<Struct1 + _ use default>();\n    use_struct1<Struct1 + Trait1 use TS1>();\n\n\n  2. Implicit type generics: function parameters and return types become generic\n\n\n  * Advantage: old-style functions can automatically work with named-impl types.\n  * Disadvantage: unsound, breaks the function's original intent.\n\n\n\n\n    fn use_struct1(s: &Struct1) {\n        s.trait1_fn();\n    }\n    // Automatically translates to\n    fn use_struct1<T: Struct1>(s: &T) {\n        s.trait1_fn();\n    }\n\n\n  * Problem 1: Multiple `Struct1`s would be forced to the same type.\n  * Problem 2: If a parameter is `i32` and becomes generic, it destroys logic inside the function that relies on that `i32` (e.g., `Add` or `PartialEq`).\n\n\n\n## Simplified Syntax\n\n  1. Named-impl selection parameter simplification\n\n\n\n\n    type Struct1Default = Struct1<i32> + use default;\n    type Struct1WithST1 = Struct1<i32> + use ST1;\n    type ComplexType = Struct1<i64> + use Struct1Fromi32<i32> + use StructFrom<_> + use ST1;\n    // The trait type can be inferred; generic parameters follow the impl name.\n\n\n## Alternative Syntax\n\n  1. Use `as` instead of `use`\n\n\n\n\n    pub impl<T> Trait1 for Struct1<T> as ST1 {\n        fn trait1_fn(&self) {\n            println!(\"named impl ST1\");\n        }\n    }\n    type Struct1Default = Struct1<i32> + _ as default;\n    type Struct1WithST1 = Struct1<i32> + Trait1 as ST1;\n\n    <Struct1<i32> as Trait1 as ST1>::trait1_fn(&s5);\n\n\n  2. Named-impl selection parameters inside `<>` after generic parameters\n\n\n\n\n    type i32AlterDisplay = i32<i32, Display use AlterDisplay>;\n    type Struct1Default = Struct1<i32, _ use default>;\n    type Struct1WithST1 = Struct1<i32, Trait1 use ST1>;\n    type ComplexType = Struct1<i64, From<i32> use Struct1Fromi32, From<_> use StructFrom, Trait1 use ST1>;\n\n    //❓ How to express this with the alternative syntax?\n    type ComplexType1 = &(i32 + Trait1 as ST1) + Trait2 as ST2;\n\n\n## Trait Inheritance Issues\n\n  1. Type bloat.\n  2. Whether a subtrait's named-impl can restrict which implementation of the supertrait is used.\n  3. More complex upcasting.\n\n\n\n\n    trait T1 {}\n    trait T2 : T1 {}\n\n    struct S;\n    impl T1 for S {}\n    impl T2 for S {}\n\n    impl T1 for S use T1S3 {}\n    impl T2 for S use T2S3 where S: T1 use T1S3 {} //❓ Optional, forces T2S3 to only be used with T1S3\n\n    // Bad news: type bloat\n    // Good news: the four types are not automatically generated; they don't exist unless written (compile-time and runtime)\n    let s1: S + _ use default = S;\n    let s2: S + T1 use T1S3 = S;\n    let s3: S + T2 use T2S3 = S; // If restricted, it is automatically inferred as the next\n    let s4: S + T1 use T1S3 + T2 use T2S3 = S;\n\n    type Invalid = S + T1 use default + T2 use T2S3; //❌ If the restrictive syntax above is present\n\n\n## Compatibility Breakage\n\n  1. FFI boundaries.\n  2. dylib exported functions.\n  3. All code that assumes trait object data pointers are the same to judge identity will break.\n\n\n\n\n    fn is_same(a: &dyn T1, b: &dyn T1) -> bool {\n    \tlet (ptr_a, vt_a) = unsafe { transmute::<_, (usize, usize)>(a) }\n    \tlet (ptr_b, vt_b) = unsafe { transmute::<_, (usize, usize)>(b) }\n    \treturn ptr_a == ptr_b;\n    }\n\n\n## Negative Implementations (negative-impls)\n\n  1. negative-impls cannot be used for named-impl\n\n\n\n\n    pub impl !Trait1 for i32 use NegTrait1 {} // ❌\n\n\n  2. Overlap checking between named-impl and negative-impls is deferred to type monomorphization time\n\n\n\n\n    #![feature(negative_impls)]\n    trait DerefMut { }\n    impl<T: ?Sized> !DerefMut for &T { }\n\n    // Overlap with other implementations (including !Trait) is NOT checked at the definition of named-impl\n    impl DerefMut for &i32 use DerefMutForI32 {} // ✅\n\n    // The overlap check between named-impl and negative-impls happens at type instantiation\n    type X = &i32 + DerefMut use DerefMutForI32; // ❌\n\n\n## GAT\n\nOrthogonality with GAT\n\n\n    type A1 = S + Iterator use SI64;  // ✅\n    type A2 = S + Iterator<Item=i64> use SI64;  // ❌\n\n\n\n    struct S;\n\n    impl Iterator for S {\n        type Item = i32;\n        fn next(&mut self) -> Option<Self::Item> { todo!() }\n    }\n\n    impl Iterator for S use SI64{\n        type Item = i64;\n        fn next(&mut self) -> Option<Self::Item> { todo!() }\n    }\n\n    fn use_iter<T: Iterator>() -> T::Item { todo!() }\n    fn use_iter_i32<T: Iterator<Item=i32>>() -> T::Item { todo!() }\n    fn use_iter_i64<T: Iterator<Item=i64>>() -> T::Item { todo!() }\n\n    use_iter::<S>();      // ✅\n    use_iter_i32::<S>();  // ✅\n    use_iter_i64::<S>();  // ❌\n\n    use_iter::<S + Iterator use SI64>();     // ✅\n    use_iter_i32::<S + Iterator use SI64>(); // ❌\n    use_iter_i64::<S + Iterator use SI64>(); // ✅\n\n\n## References\n\n  * [Pre-RFC] Selectable Trait Implementations\n  * [Pre-RFC] Scoped `impl Trait for Type`\n  * Looking for RFC coauthors on \"named impls\"\n  * Named impls and impl generics\n\n",
  "title": "Named impl with Implementation Selection Variant"
}