Pre-RFC: KnownTypeId

This is my first RFC, providing a way for a trait to get the TypeId when Self: 'static while still being sound, and without breaking backwards compatibility. Could I get some feedback? Thanks! https://github.com/leo60228/rfcs/blob/master/text/0000-knowntypeid.md

1 Like

I don't really understand how this can be more sound than Any if it's almost the same as Any except that it removes a restriction from implementors. Any requires Self: 'static for a good reason: there's currently no way to express the difference (at runtime) between types of the same base type but different lifetimes using a TypeId. Thus, allowing non-'static types to be downcast based on identical TypeIds would enable one to essentially transmute away lifetimes. AFAICT the addition of an Any-like trait without this restriction would only introduce a soundness hole.

This isn't more sound than Any, but it is easier to use because it doesn't require 'static at the trait level. What this allows is making other traits act like Any by just adding it as a bound on other traits. For example, this would allow sound Error downcasting without a breaking change. This seems like a good idea, and I think that we should consider this a bit more.

3 Likes

The Self: 'static bound was not removed, it was moved to KnownTypeId::type_id.

2 Likes

Oh, right. It seems that I completely missed that part.

The trait KnownTypeId is implemented for all T so it can not be manually implemented at all (contrary to Error which can). And even if specialization were to allow it, it was marked unsafe so that providing such an implementation could be defined as not being sound.

I think the RFC could do with maybe a short example of how a library could use this to provide downcasting on a trait that doesn't require Any.

4 Likes

Downcasting isn't even available on a trait that explicitly requires Any as downcast_ref is only on dyn Any directly, not the trait and upcasting isn't a thing yet.

So with or without this we still need an easy and safe way to do downcasting on other traits.

I try making some generic free functions but since dyn NotAny + 'static impls Any no error message is given for missuses.

I've added an example of this.

1 Like

The goal of this was to make it possible to soundly support downcasting on an arbitrary trait, not safely. As far as I understand, it's not possible to automatically support downcasting on any trait object without a macro (which could be trivially implemented with this RFC).

Traits wanting to support downcasting can add it as a supertrait, without breaking backwards compatibility.

If it is implemented for all types, why does it even have to be added as a supertrait?

Oh, I guess the point is that self.type_id will consult the vtable to figure out the ID of the "actual" type. It took me a bit of staring at this and wondering why you couldn't just call that. This should be explained better in the RFC.

2 Likes

I added a sentence and playground link explaining this.

I wasn't aware that was possible. Thanks! I'll update the examples.

Never mind, I misunderstood your post. Sorry!

Thanks!

I think it would be a good idea to also add a comment saying basically the same thing in your code in fn is, to answer the question right at the place where it comes up instead of 5 paragraphs later.

2 Likes

Done.

1 Like

Do you guys think this looks ready to PR?

Could we move the is function into the trait like so

trait WithTypeId {
    fn tye_id(&self) -> TypeId where Self: 'static {
        TypeId::of::<Self>()
    }
    
    fn is<T: 'static>(&self) -> bool where Self: 'static {
        self.type_id() == TypeId::of::<T>()
    }
}
1 Like

That wouldn't work, since is wouldn't be object safe.

1 Like

Right, forgot about that!

1 Like