# Extremely bad solutions to the Any 'static requirement

**URL:** <https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494>\
**Category:** language design\
**Created:** [June 4, 2020, 8:31pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494 "2020-06-04T20:31:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 4, 2020, 8:31pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/1 "2020-06-04T20:31:51Z")

</div>

Every once in a while there comes a use case where the functionality of Any would be desired in a non-static context. Unfortunately, one of the sticky points in the Rust library is that `TypeId::of<T>` requires that the lifetime of T to be 'static. Here are two of the incredibly fun solutions I have found and discovered.

Dtolnay, the genius they are, exploits the monomorphization of functions to use the function pointers as IDs:

```rust
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct TypeId {
    id: usize,
}

impl TypeId {
    pub fn of<T: ?Sized>() -> Self {
        TypeId {
            id: TypeId::of::<T> as usize,
        }
    }
}

```

My solution is different, and uses [type\_name](https://doc.rust-lang.org/std/any/fn.type_name.html). It relies on two things:

- `type_name` conveniently left out the 'static bound
- `type_name` returns a _`&'static str`_, which means that that string is valid for the lifetime of the program.

Here it is (all the stuff that makes this not contrived has been omitted):

```rust
pub trait AnyLike<'a, T>
where
    T: 'a,
{
    fn type_id(&self) -> usize {
        std::any::type_name::<Self>().as_ptr() as usize
    }
}

```

Assuming that `type_name` prints out the fully qualified path of each type (which it is NOT guaranteed to do), this works across crates! I wouldn't recommend it though.

It's hard to believe I need to actually use this to do something legitimate, but I do, and these two solutions are all I have.

Which is fine for me, as I've carefully thought about the assertions and any possible safety issues. This code is primarily going to be used for unit testing, and I know that all of the types I'm using this on will have distinct names even if the paths are squished. Also, none is named with the prefix of another, which I suppose could also produce a false positive.

However, I'm worried that other people might have not thought about their problems as deeply as I have, and we may end up being de facto required to have type\_name print the full path all of the time before we know it.

---

<div class="post-metadata">

**Author:** ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)\
**Post date:** [June 4, 2020, 8:52pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/2 "2020-06-04T20:52:53Z")

</div>

I don't endorse this, despite my name being in the post. The code you pasted is from one of my projects where it is used as a debugging aide only, not compiled into the project unless opted in by a feature called "unstable-debug" for debugging purposes.

---

<div class="post-metadata">

**Author:** ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)\
**Post date:** [June 4, 2020, 8:57pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/3 "2020-06-04T20:57:11Z")

</div>

The same function `type_name::<T>` can have different addresses (and actually different behavior too) in different places. See [https://github.com/rust-lang/rfcs/issues/1428#issuecomment-450535964](https://github.com/rust-lang/rfcs/issues/1428#issuecomment-450535964) for an example of different behavior of the same function even within the same source file.

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 4, 2020, 9:09pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/4 "2020-06-04T21:09:46Z")

</div>

I hope that my post didn't come across as if I seemed to imply that you were tacitly endorsing it, I certainly don't recommend using either - I intended to illustrate some work arounds that have been used in the past, and why I think it ultimately is a problem that `type_id` has a `'static` requirement. I only intended to cite you.

Indeed, `type_name` can have different addresses. Fortunately for me it's never used twice, so I think I can still use it for this.

I'm personally only using this so that I can add more unit tests, and unit tests breaking in the future is not as important as getting code working and tested now. It will never go into production.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [June 4, 2020, 9:19pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/5 "2020-06-04T21:19:09Z")

</div>

> [@LateNiteMartyParty](#):
>
> It will never go into production.

Many bad ideas in production are preceded thusly...

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [June 4, 2020, 9:23pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/6 "2020-06-04T21:23:36Z")

</div>

> [@LateNiteMartyParty](#):
>
> It's hard to believe I need to actually use this to do something legitimate, but I do, and these two solutions are all I have.

Would you mind elaborating a bit on the legitimate use case you have? Iʼve only seen hints that itʼs related to unit testing in this thread so far. Iʼm mostly just curious, but I guess presenting your use case here might also help convincing people that there is need for an officially supported way to identify non-static types (while ignoring their lifetimes).

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 4, 2020, 9:40pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/7 "2020-06-04T21:40:41Z")

</div>

Sure, I will do my best. I don't think I can go far into the details but I'll give an overview.

I work in compilers, and I have a function that looks like this:

```rust
fn parse<'a>(input: &'a str) -> Box<dyn Expression<'a> + 'a>;

```

It is incredibly convenient when writing compilers to have the output be an opaque AST node. Plus, by attaching the lifetime I can still avoid string copies.

Edit: I mis-characterized the problem. Here it is again, better explained.

Basically, I would like to do the following. When I define I node, I would like to have it automatically derive `PartialEq`, like the following:

```rust
#[derive(partialEq)]
struct Add<'a> { 
    arg1: Box<dyn Expression<'a> + 'a>,
    arg2: Box<dyn Expression<'a> + 'a>,
}

```

This is so that when I write unit tests, I can do the following:

```rust
fn test() { 
    use ast::{add, literal};
    assert_eq!(parse("5 + 5"), add(literal("5"), literal("5"));
}

```

It's not possible to do this without the workarounds I described. In fact, even with the workaround, equality is only possible if the lifetime is shared, making this safe.

It is possible to do this with Debug to a String, but that requires extra allocation and is confusing because now the node has to derive Debug or Display.

---

<div class="post-metadata">

**Author:** ![dhardy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhardy/32/2399_2.png) [@dhardy](https://internals.rust-lang.org/u/dhardy)\
**Post date:** [June 6, 2020, 10:49am UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/9 "2020-06-06T10:49:53Z")

</div>

IIUC there are two sides to this problem:

1. `type_id` is supposed to unique to a type; since lifetime parameters are part of the type, it should also depend on the lifetime (even though it isn't needed for this application); note that in general it is hard to ensure that a new parameterisation of a type with a different lifetime would generate a different `type_id`, thus `Any` takes the conservative restriction of requiring `'static`. (Simply ignoring lifetimes would be unsafe by allowing lifetime extension in a downcast.)
2. Effectively what you want for the comparison is to cast both objects to a fresh lifetime which does not outlive either source lifetime. For this, Rust would need some type of higher-kinded lifetime generics (especially since it is unknown in general how many lifetime parameters the type has). It's the same problem as [userspace reborrows](https://github.com/rust-lang/rfcs/pull/2364).

So, your "hack" here generates a `type_id` which is independent of the lifetime, thus could be used to extend lifetime in a downcast (violating memory safety).

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [June 6, 2020, 11:20am UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/10 "2020-06-06T11:20:53Z")

</div>

I think that it is fine to generate type ids for `non-'static` types, so long as you can't use those types in conjunction with `Any` (or similar traits). So long as we acknowledge that they will only be unique if we ignore lifetimes.

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 6, 2020, 8:12pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/11 "2020-06-06T20:12:51Z")

</div>

Agreed on point one. I would think that generic objects with different lifetime params would have different type\_ids.

On point two, I've walked back a bit on this. I don't actually need to cast the objects to a fresh lifetime. Downcasting to an object that has the same lifetime is sufficient, since the comparison is only used when the lifetime is `'static` or otherwise the same. Here is my custom downcasting code to illustrate this:

```rust
impl<'a, TS> dyn Expr<'a, TS> + 'a
where
    TS: Redacted + 'a,
{
    /// This is important: it must share the same lifetime!
    fn is<T: Expr<'a, TS> + 'a>(&self) -> bool {
        // Code copied from Any but uses pseudo_type_id
    }

    fn downcast_ref<T: Expr<'a, TS> + 'a>(&self) -> Option<&T> {
        // Code copied from Any 
    }
}

```

Additionally, since the objects effectively "know" their own types via their vtables, it is only necessary to downcast the rhs object. The algorithm for comparison is as follows:

```rust
impl<'a, T, TS> NodeEq<'a, TS> for T
where
    T: PartialEq<Self> + Eq + Expr<'a, TS> + 'a,
    TS: Redacted + 'a,
{
    default fn node_eq(&self, rhs: &(dyn Eval<'a, TS> + 'a)) -> bool {
        rhs.downcast_ref::<Self>().map_or(false, |rhs| self == rhs)
    }
}

```

Which can then be used to implement `for<'a, TS> Box<dyn Expr<'a, TS> + 'a>: PartialEq<Self>`

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [June 6, 2020, 10:10pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/12 "2020-06-06T22:10:33Z")

</div>

This doesn't work because this allows you to transmute lifetimes in safe code. For example, if a type has an unrelated lifetime

> **[\[Solved\] Variance of \`dyn Trait + 'a\`](https://users.rust-lang.org/t/solved-variance-of-dyn-trait-a/39733/15)**
>
> That's indeed the same intuition I've finished by having (much better phrased, obviously 👌), c.f., the example in my previous code: struct Struct\<'short, 'a : 'short, 'b : 'short\> { short: &'short u8, a: &'a u8, b: &'b u8,...

```rust
struct Struct<'short, 'a : 'short, 'b : 'short> {
   short: &'short u8,
   a: &'a u8,
   b: &'b u8,
}

```

You code would allow you to convert from `Struct<'short, 'a, 'b>` to `Struct<'short, 'b, 'a>` via `dyn Expr<'short, _>`. This is _unsound_.

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 6, 2020, 11:17pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/13 "2020-06-06T23:17:23Z")

</div>

Hmm... you're right, and that's unfortunate for me. I had hoped that `Expr` having a method with the signature `fn ex(self: Box<Self>)` would make such constructs impossible to create, but that's clearly not the case.

I still might keep it, because while it is unsound I know that none of the structs that implement Expr have any additional lifetime.

Actually, thinking about this further, I think that it's possible for me to enforce this constraint by adding the following bounds to `NodeEq` and `dyn Expr<'a, TS> + 'a`: `where 'a: 'static`. This would ensure that for

```rust
struct Struct<'short, 'a : 'short, 'b : 'short> {
   short: &'short u8,
   a: &'a u8,
   b: &'b u8,
}

```

that `'short: 'static` and `'a: 'static` and `'b: 'static`.

Since I need these for unit tests, I only need this for the static lifetime, so I think that this might fix the unsoundness? This is probably no different than just implementing these for the 'static lifetime, giving me `Any` along with it.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [June 7, 2020, 12:24am UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/14 "2020-06-07T00:24:34Z")

</div>

> [@LateNiteMartyParty](#):
>
> Actually, thinking about this further, I think that it's possible for me to enforce this constraint by adding the following bounds to `NodeEq` and `dyn Expr<'a, TS> + 'a` : `where 'a: 'static` . This would ensure that for

And we're back at `Any`

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [June 7, 2020, 8:33am UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/15 "2020-06-07T08:33:15Z")

</div>

> [@LateNiteMartyParty](#):
>
> monomorphization of functions to use the function pointers as IDs

Note that Rust compiles functions with `unnamed_addr`, which means that there is no 1:1 mapping between the address of a function and its source-level identity. Different functions can have the same address (if their assembly is the same and they get merged by LLVM), and potentially the same function might even have different addresses when viewed from different codegen units (not sure about this... it definitely happens for vtables though).

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [June 7, 2020, 8:53am UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/16 "2020-06-07T08:53:20Z")

</div>

> [@RalfJung](#):
>
> potentially the same function might even have different addresses when viewed from different codegen units (not sure about this... it definitely happens for vtables though).

Also happens for generic and `#[inline]` functions.

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 8, 2020, 9:58pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/17 "2020-06-08T21:58:42Z")

</div>

Unfortunately, it seems like even doing this requires a pseudo-type-id. I tried the following, but the issue was immediately apparent:

```rust
impl<TS> dyn Expr<'static, TS> + 'static
where
    TS: TypeSystem + 'static,
{
    /// This is important: it must share the same lifetime!
    pub fn is<T: Expr<'static, TS> + 'static>(&self) -> bool {
        let t = TypeId::of::<T>();
        let concrete = <Self as Any>::type_id(self);
        t == concrete
    }

    pub fn downcast_ref<T: Expr<'static, TS> + 'static>(&self) -> Option<&T> {
        if self.is::<T>() {
            unsafe { Some(&*(self as *const dyn Eval<'static, TS> as *const T)) }
        } else {
            None
        }
    }
}

```

`type_id` isn't included in the vtable of `Expr` because I can't require that `Expr: Any` The `TypeId` given to concrete is the one of `dyn Expr<'static, TS>`, not the `TypeId` of the concrete type.

I'm forced to have `Expr` include a `type_id` function, but since `Expr` is not always static, the type id has to be a psuedo type id.

I don't think there's any way around this unfortunately, but at least thankfully this code shouldn't be _unsound_, and I can still do what I want. Unfortunately I don't have the ability to automatically derive `PartialEq` now, which was convenient, but I should be able to write a proc macro that does the same thing.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [June 8, 2020, 10:01pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/18 "2020-06-08T22:01:59Z")

</div>

> [@LateNiteMartyParty](#):
>
> because I can't require that `Expr: Any`

Why not? If that's the case you can put

```rust
fn typeid(&self) -> TypeId where Self: 'static { TypeId::of::<Self>() }

```

in your `Expr` trait, and base things off of that. (Do you really need a trait for `Expr`, I would assume a enum is a better fit, because there are a limited number of possible expressions forms)

---

<div class="post-metadata">

**Author:** ![LateNiteMartyParty](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/latenitemartyparty/32/4089_2.png) [@LateNiteMartyParty](https://internals.rust-lang.org/u/LateNiteMartyParty)\
**Post date:** [June 8, 2020, 10:48pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/19 "2020-06-08T22:48:24Z")

</div>

Wow, I didn't have any idea that it was possible to have extra bounds on Self for trait methods. I thought those bounds were lifted to the top of the item.

As to the second question, an enum is what we were using before, so it's certainly possible to use. The issue is that while there is a limited number of possible expressions, there are a lot of them, and this provides a convenient way to add and extend functionality without having to add variants to one massive enum.

If this was a performance bottleneck, I don't think that this would be a reasonable change. However, the ability for different people to add different operators without interfering with other peoples work is a win for us.

Another the major reason is that, while I can't get into what TS is, it would be very useful for us to add variants to the Expr that only apply to one TS (or have different impls per concrete TS). There are other ways to do this, but they get really messy.

Thanks for your help Yato, you're amazing as always.

---

<div class="post-metadata">

**Author:** ![JeffBurdges](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jeffburdges/32/2116_2.png) [@JeffBurdges](https://internals.rust-lang.org/u/JeffBurdges)\
**Post date:** [June 8, 2020, 11:10pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/20 "2020-06-08T23:10:57Z")

</div>

In release builds, I'd expect dtolnay's `TypeId` should satisfy `TypeId::of::<T>() == TypeId::of::<S>()` for _all_ `T` and `S` because any inequalities represent an optimization failure. We've enough reusable or empty default methods ala `trait Foo { fn foo(&_self) {} }` that rustc should optimize them away.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [June 9, 2020, 4:21pm UTC](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494/21 "2020-06-09T16:21:41Z")

</div>

Such optimization would require LTO.

[Next page](https://internals.rust-lang.org/t/extremely-bad-solutions-to-the-any-static-requirement/12494.md?page=2)
