# Inline specialization

**URL:** <https://internals.rust-lang.org/t/inline-specialization/24679>\
**Category:** language design\
**Created:** [October 16, 2026, 10:48pm UTC](https://internals.rust-lang.org/t/inline-specialization/24679 "2026-10-16T22:48:14Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ds84182](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ds84182/32/12379_2.png) [@ds84182](https://internals.rust-lang.org/u/ds84182)\
**Post date:** [October 16, 2026, 10:48pm UTC](https://internals.rust-lang.org/t/inline-specialization/24679/1 "2026-10-16T22:48:14Z")

</div>

**Warning** : This is a half-baked idea.

There are many soundness issues with specialization in its current form. I would like to propose an alternative. While it may not be as powerful, it should be sound due to its simplicity.

# `where` clause statement

Typically, specialization is used to implement special behavior for types implementing a specific trait. Instead of replacing the impl with a new one (requiring trait selection to be vigilant wrt overlapping impls), I propose a statement with similar semantics as C++ `if constexpr`, but exclusively for trait bounds:

```rust
pub trait CloneInto: Clone {
  // An implementation on Vec can reuse the existing allocation.
  fn clone_into(&self, dst: &mut Self);
}

pub fn clone_into<T: Clone>(value: &T, dst: &mut T) {
  where T: CloneInto {
    // Within this block, T also implements CloneInto.
    value.clone_into(dst)
  } else {
    // Otherwise, fall back to Clone.
    *dst = value.clone();
  }
}

```

To summarize:

- At compile time, if the specified bounds are true the given block is used. Others are discarded.
- The types implement traits from the where bounds within the block.
- All bounds are supported here.
- _If possible_, simple type equality bounds could be supported.
- Like if statements, where clause statements also have else and else where statements.

One downside (upside) is that this does not modify trait selection. While this is strictly less powerful than trait-level specialization, it meets most of the demand and doesn't touch the trait solver (which seems to be a common way to cause unsoundness).

More concretely, this still does not allow blanket trait impls to be overridden (which is why `clone_into` is a free fn). Specialization on blanket trait impls can be emulated by using two traits: one for the blanket impl, and one for the specialization.

While `try_as_dyn` also exists, I think this approach supercedes it. The traits do not need to be dyn compatible, so traits like `Default` or bytemuck marker traits like `Zeroable` can be specialized upon.

---

<div class="post-metadata">

**Author:** ![ProgramCrafter](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programcrafter/32/13494_2.png) [@ProgramCrafter](https://internals.rust-lang.org/u/ProgramCrafter)\
**Post date:** [October 16, 2026, 11:32pm UTC](https://internals.rust-lang.org/t/inline-specialization/24679/2 "2026-10-16T23:32:28Z")

</div>

> [@ds84182](#):
>
> - Like if statements, where clause statements also have else and else where statements.

Is the query `T: CloneInto` even decidable, to allow the else branch to assume that `T: !CloneInto`? It might not be (it is semidecidable though), then your code can non-deterministically go to the else branch...

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [October 17, 2026, 2:23am UTC](https://internals.rust-lang.org/t/inline-specialization/24679/3 "2026-10-17T02:23:10Z")

</div>

> [@ProgramCrafter](#):
>
> It might not be (it is semidecidable though), then your code can non-deterministically go to the else branch...

Not to mention that any generic callers of `clone_into` would need a `T: ?CloneInto` (or something) to pass along the "does it `impl CloneInto`" bit as they'd otherwise all fall into the `else` block. If the `T` is inspected regardless of the caller's bounds, you have:

```rust
fn is_static<T>() -> bool {
    where T: 'static {
        true
    } else {
        false
    }
}

```

which I'm sure someone could use to be unsound where they only know `T: 'a`.

---

<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:** [October 17, 2026, 1:29pm UTC](https://internals.rust-lang.org/t/inline-specialization/24679/4 "2026-10-17T13:29:30Z")

</div>

This has already been discussed multiple times, e.g. [in this recent thread](https://internals.rust-lang.org/t/pre-rfc-compile-time-conditional-branching-on-trait-implementations/24623). Given that:

- this approach by itself does not fix specialization's unsoundness. That comes from specializing code on lifetimes, and this approach still allows that (consider if I e.g. do `impl CloneInto for &'static MyType`, your code would have to detect that lifetime at monomorphization time). The approach that `try_as_dyn` takes is to sometimes return `None` (in your case take the `else` branch) even if the type does implement the given trait.

- `try_as_dyn` does not need to interact with the language syntax, nor does it interact with the param env in functions. This makes it simplier to implement and experiment with. Nothing prevents the final feature to look like what you described, but for experimenting a library-only solution is much more practical.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [October 17, 2026, 11:56pm UTC](https://internals.rust-lang.org/t/inline-specialization/24679/5 "2026-10-17T23:56:33Z")

</div>

I'm sorry, but when discussing a solution for a problem that is _so_ widely explored and discussed (and is [actively worked on](https://rust-lang.zulipchat.com/#narrow/channel/614298-t-types.2Fspecialization/topic/Use.20case.20survey/with/630273600)), I believe it makes sense to _understand what the blockers are_. Which if you would do, you would realize that the problem is not the syntax, your approach is not materially better than `try_as_dyn()` (and was already proposed FWIW), and this post does nothing to solve the hard problems.
