{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreih5r5geefkqhdgsa5vp5kyurzenvt3l7ef6n5ojpkmbj6kspxqkpu",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mifop27acw62"
  },
  "path": "/t/yet-another-half-baked-idea-for-working-around-the-orphan-rule/24121#post_5",
  "publishedAt": "2026-03-31T20:26:52.000Z",
  "site": "https://internals.rust-lang.org",
  "textContent": "Hi everyone, and thank you for these insightful technical points.\n\ndlight:\n\n> What really sucks is wrapping/unwrapping types when _using_ the types.\n\nThis is precisely the friction point Facets aim to eliminate. Consider `NonNull<T>`. Today, if you have a newtype, you are forced to map/unwrap the container. With Facets, you can cast the nested type directly:\n\n  1. **Strict Upcasting:** If `T\\f1` is a descendant of `T\\f2`, then `NonNull<T\\f1>` can be cast to `NonNull<T\\f2>` as a no-op.\n  2. **Structural Invariance:** By marking `NonNull` with `struct NonNull<#[structural()] T>`, the author allows casting between any facets of `T`. Since `NonNull` does not rely on any specific trait of `T` to maintain its \"not null\" invariant, this is perfectly safe and removes the need for any manual wrapping.\n\n\n\ndlight:\n\n> Also, a small comment on syntax. I think that using punctuation in `Type\\foo` isn't a good tradeoff.\n\nI have no \"religious\" preference regarding the syntax. If the semantics of the design are deemed viable, we will have plenty of time to \"bikeshed\" the notation. The priority now is to determine if the underlying logic holds water.\n\nSkiFire13:\n\n> This breaks down when the trait implementation names the implementing type somewhere else.\n\nI apologize, as my initial presentation was indeed unclear on this point. In my model, facet inheritance involves a systematic substitution of `Self`.\n\nSpecifically, `impl PartialEq<Self> for i32` on the base type is inherited as `impl PartialEq<Self> for i32\\foo` on the facet. This ensures that `Eq` remains valid. If an implementation explicitly names the base type (e.g., `i32`) instead of `Self`, the facet inherits it as-is.\n\nzackw:\n\n> What I want [...] is a way to pass `unix_path::Path` objects directly to `rustix::fs::open` [...] with _no_ extra ceremony at each callsite.\n\nBecause a facet is a distinct nominal type, you \"own\" it and can implement the external trait for it:\n\n\n    // 1. Define a local facet for the external type\n    facet WithArg for unix_path::Path;\n\n    // 2. Implement the external trait for your local facet (Legal!)\n    impl rustix::path::Arg for Path\\WithArg { /* ... */ }\n\n    fn main() {\n        let path = get_path(); // Assume this is a unix_path::Path\n        let path = path as unix_path::Path\\WithArg; // no-op\n        rustix::fs::open(path, O_RDONLY, M_IGNORED);\n    }\n\n\nI suspect that requiring `path as unix_path::Path\\WithArg` still constitutes \"ceremony\" from your perspective. While implicit coercion could be envisioned to bridge this gap, I believe it would introduce too much \"magic\" and obscure the transition between nominal identities. I opted for an explicit cast to maintain predictability and avoid \"spooky action at a distance,\" which I consider a necessary trade-off for a system that strictly preserves global coherence.",
  "title": "Yet another half-baked idea for working around the orphan rule"
}