# Idea: include \`TypeId\` in all trait object vtables

**URL:** <https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666>\
**Category:** language design\
**Created:** [March 31, 2025, 12:43am UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666 "2025-03-31T00:43:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [March 31, 2025, 12:43am UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/1 "2025-03-31T00:43:30Z")

</div>

Sometimes, one finds oneself wanting to combine the functionality of the [`dyn Any`](https://doc.rust-lang.org/std/any/trait.Any.html#impl-dyn+Any) with that of `dyn SomeOtherTrait`. However, this currently requires custom `unsafe` code, or third-party libraries like [mopa](https://crates.io/crates/mopa).

It would be convenient if this functionality was built in to all trait objects. This could be accomplished by including the `TypeId` of the concrete type inside every trait object vtable. The `Any` trait could then become a magic lang item, with the implementation of `dyn Any` making use of this vtable entry. This would make it possible for any `'static` trait object to upcast to `dyn Any`.

## Example

```rust
use core::any::Any;

fn foo(obj: &dyn Debug) {
    dbg!(obj);
    if let Some(num) = obj.downcast_ref::<i32>() {
        dbg!(num + 17);
    }
}

```

## Miscellanea

- This would change the behavior of `<dyn SomeOtherTrait as dyn Any>::type_id()` (where `SomeOtherTrait` does not have `Any` as a supertrait). Previously, this would give the `TypeId` of the type `dyn SomeOtherTrait`; after this change, it would give the `TypeId` of the underlying concrete type.
- This change might help resolve longstanding soundness bug [#57893](https://github.com/rust-lang/rust/issues/57893), because an explicitly magical `dyn Any` would no longer need to rely on an incoherent impl for its functionality. However, we would still have to find a solution for reimplementations of `Any` in the ecosystem (like the aforementioned [mopa](https://crates.io/crates/mopa)), before the issue could be fixed for good.
- One potential drawback is the impact on binary sizes. Adding a single entry for the `TypeId` shouldn’t bloat vtable sizes by too much. However, it would prevent de-duplication of vtables that were previously identical.

---

<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:** [March 31, 2025, 6:56pm UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/2 "2025-03-31T18:56:11Z")

</div>

It doesn't require unsafe code:

```rust
use std::fmt::Debug;
use std::any::Any;

trait Foo: Any + Debug {
    fn as_any(&self) -> &(dyn Any + 'static);
}

impl<T: Any + Debug> Foo for T {
    fn as_any(&self) -> &(dyn Any + 'static) {
        self
    }
}

```

And with trait upcasting it will become even more convenient (and performant).

Doing it for all traits will violate the zero-cost abstraction principle.

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [March 31, 2025, 7:05pm UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/3 "2025-03-31T19:05:50Z")

</div>

Yes, you are correct that trait upcasting makes this easier.

However, that approach still has limitations. Notably, it only works if you control how the trait object is produced. If you get a `dyn SomeTrait` from an API you don’t control, you cannot downcast it.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [April 6, 2025, 12:34pm UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/4 "2025-04-06T12:34:06Z")

</div>

> [@Jules-Bertholet](#):
>
> One potential drawback is the impact on binary sizes. Adding a single entry for the `TypeId` shouldn’t bloat vtable sizes by too much. However, it would prevent de-duplication of vtables that were previously identical

This vtable bloating would in general be bad for embedded (even if deduplication could work). It is not a zero cost abstraction, in fact everyone would have to pay for it, even if they don't use it. I don't think that is acceptable, especially for such a niche feature.

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [April 6, 2025, 11:59pm UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/5 "2025-04-06T23:59:13Z")

</div>

I think this depends heavily on what the impact would be in practice. For example, people were concerned about whether the recently-stabilized dyn trait upcasting feature would bloat vtables too much, but [data showed the impact was minimal](https://github.com/rust-lang/rust/issues/112355). However, it’s possible that the size increase from this would be worse? It would be a smaller impact per trait, but bloating all traits instead of just a few. Hard to tell without testing…

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [April 7, 2025, 12:30am UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/6 "2025-04-07T00:30:54Z")

</div>

Is there a simple way to make this opt-in? Make a (probably magic) `Typed<dyn Trait>`/`Tagged<dyn Trait>`/`dyn🚲 Trait` that just stores a type id?

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [September 29, 2026, 12:30am UTC](https://internals.rust-lang.org/t/idea-include-typeid-in-all-trait-object-vtables/22666/7 "2026-09-29T00:30:56Z")

</div>

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
