{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreig5lggdiprt2nhm56u62dztp2gegxmi2x5ilwnuuxdxdd3zpq5tim",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mid6osifdca2"
  },
  "path": "/t/yet-another-half-baked-idea-for-working-around-the-orphan-rule/24121#post_1",
  "publishedAt": "2026-03-30T21:34:21.000Z",
  "site": "https://internals.rust-lang.org",
  "textContent": "Hi everyone,\n\nI’ve been working on a preliminary idea to address some of the friction caused by the orphan rule, which I’ve tentatively named facets. I want to be upfront: this is very much a \"half-baked\" proposal. I have not conducted an exhaustive search of all previous RFCs or alternative designs, and I am fully aware that I might be reinventing the wheel or suggesting something that has already been dismissed for good reasons. Before I invest more time into formalizing this, I would value the community's feedback on two specific points:\n\n  1. Is there already a proposal or an established design (even a rejected one) that covers this exact territory?\n  2. Does the core mechanism seem like a direction worth investigating, or are there immediate blockers regarding complexity or safety that make this a non-starter?\n\n\n\nHere is the current draft of the idea:\n\n# Facets and Controlled Structural Subtyping\n\n## Summary\n\nThis document introduces **Facets** , a variation on the _newtype_ pattern that allows downstream crates to attach additional trait implementations to foreign types without violating Rust’s coherence rules.\n\n## Motivation\n\nA common critique of proposals addressing the orphan rule is the risk of breaking global coherence. Designs that allow concurrent or scoped implementations often lead to ambiguous trait resolution or split-world scenarios where different parts of the same binary see different implementations for the exact same type. Facets explicitly reject this direction. Instead of weakening the orphan rule, Facets leverage Rust's existing nominal type system. This approach is a variation of the newtype pattern. Facets do not aim to make the orphan rule more permissive for a single type; they aim to make the creation and use of \"almost-identical\" nominal types ergonomic and zero-cost most of the time.\n\n## Core Design\n\n### Facet Types\n\nA Facet is declared for an existing type `Hello` as follows:\n\n\n    facet foo for Hello;\n\n\nAt usage sites, the type `Hello` under facet `foo` is written as `Hello\\foo`. The type `Hello` itself is considered the **default facet**. Facets based on the same base type are said to be **related**. Facets have the following properties:\n\n  * `Hello\\foo` is a distinct nominal type from any other related facet.\n  * All related facet types share the exact same memory representation.\n  * Every complex type involving a facet (e.g., `Option<Hello\\foo>`) has the same memory representation as the type obtained by replacing the facet with any other related facet (e.g., `Option<Hello>`).\n  * No implicit conversions exist between related facet types.\n\n\n\n### Facet Inheritance\n\nThe declaration syntax above is a special case of the more general syntax:\n\n\n    facet foo: bar for Hello;\n\n\nWhere `bar` must be a pre-existing related facet. In this case, `foo` is a **child** of `bar`. If no parent is specified, it defaults to the default facet.\n\nA facet `baz` is an **ancestor** of `foo` if there exists a chain of parent relationships from `foo` to `baz`.\n\nWhen `foo` is a child of `bar`, it **inherits** all inherent and trait implementations defined on `Hello\\bar`. Mechanically, the compiler behaves as if identical implementations were generated for `Hello\\foo`.\n\n### Explicit Implementations for Facets\n\nIn the crate where it is declared, a facet `foo` can provide new implementations for traits. An implementation may define a brand-new trait or **override** an implementation already provided by an ancestor. This ensures that adding implementations to an ancestor in the future cannot break existing descendants.\n\nWe say that `foo` **strictly inherits** from an ancestor `baz` if `foo` does not override any implementations provided by `baz`.\n\n### Selective Trait Inheritance\n\nA facet can explicitly reuse a specific trait implementation from another related facet:\n\n\n    impl Trait for Hello\\foo: qux;\n\n\nThis mechanism may override an implementation of `Trait` inherited from an ancestor of `foo`. In that case, `foo` no longer strictly inherits from that ancestor, as it now has a distinct implementation.\n\n### Implementation Sharing\n\nTwo facets `Hello\\f1` and `Hello\\f2` **share the implementation of a trait** `Trait` if the compiler can prove they use the same implementation block through full or selective inheritance. This is the case if:\n\n  * One is a child of the other and does not override `Trait`.\n  * One selectively inherits `Trait` from the other.\n  * They both share the implementation with a common third facet (transitivity).\n\n\n\n* * *\n\n## Conversion Semantics\n\nThe core principle of facet conversion is **safety through ownership and immutability**. Conversions are zero-cost at runtime but strictly governed by the compiler to prevent invariant violations.\n\n### 1. Fundamental Types (Owned and References)\n\nType | Conversion | Rationale\n---|---|---\n**Owned Value** (`Hello\\f1`) | **Universal** | Safe. The owner has exclusive control; all invariants are explicitly chosen by them.\n**Shared Reference** (`&Hello\\f1`) | **Universal** | Safe. Immutability ensures the data cannot be modified in a way that breaks its invariants.\n**Unique Reference** (`&mut Hello\\f1`) | **Forbidden** | **Strictly invariant.** Prevents redefining implementations for mutating methods, which could break internal invariants.\n\n### 2. Wrappers parameterized by Facets\n\nWe call a type expression with a generic type parameter `T` a _wrapper type_. This can be a simple generic type such as `Option<T>` or a more complex type expression such as `HashMap<usize, Vec<Option<T>>>`. The type parameter `T` may appear in multiple positions, as in `HashMap<T, T>`.\n\nThe key question is to determine when it is safe to convert `Wrapper<Hello\\f1>` into `Wrapper<Hello\\f2>`.\n\nAuthors of generic types can opt into flexible casting by declaring, for each type parameter, which traits are required to preserve internal structure. For example:\n\n\n    struct HashMap<\n        #[structural(Hash, Eq)] K,\n        #[structural()] V\n    > { ... }\n\n\nHere, `Hash` and `Eq` are **structural traits** for parameter `K`. Parameter `V` has no structural traits. A type parameter without a `#[structural(...)]` attribute is said to be **unmarked**.\n\nType | Conversion | Rationale\n---|---|---\n**Owned unmarked wrapper types** (`Wrapper<Hello\\f1>`) | **Strict upcast** | Safe. The result supports fewer operations than the input. This is a **one-way** operation because the original wrapper is consumed.\n**Owned marked wrapper types** (`Wrapper<#[structural(...)] Hello\\f1>`) | **Implementation sharing of structural traits** | Safe. Permitted if the compiler can prove that facets `f1` and `f2` share the same implementation for all structural traits.\n**Shared references to unmarked wrapper types** (`&Wrapper<Hello\\f1>`) | **Strict upcast** | Safe. Upcasting to `&Wrapper<Hello\\f2>` is permitted under strict inheritance. Immutability prevents inserting incompatible facets.\n**Shared references to marked wrapper types** (`&Wrapper<#[structural(...)] Hello\\f1>`) | **Implementation sharing of structural traits** | Safe. Permitted if facets `f1` and `f2` share the same implementation for all structural traits.\n**Unique references to any wrapper types** (`&mut Wrapper<Hello\\f1>`) | **Forbidden** | **Strictly invariant.** Allowing facet changes through a mutable reference could violate the original owner’s invariants.\n\n### 3. Parallel Casting\n\nIt is valid to change multiple generic parameters simultaneously if each individual cast is valid. For example, casting `HashMap<Key\\f1, Value\\g1>` to `HashMap<Key\\f2, Value\\g2>` is permitted if both the `K` parameter cast and the `V` parameter cast satisfy their respective structural or strict inheritance requirements.",
  "title": "Yet another half-baked idea for working around the orphan rule"
}