Why doesn't trait get inherent methods from supertrait?


#1

The trait Any has a method is. If I define another trait trait Trait: Any. &Trait does not get the is method. play

I know that Trait: Any just means that anything which implements Trait also implements Any. So anywhere you use Trait, you can call methods defined on Any as well.

Since All Trait is also an Any, I don’t understand why it’s not possible to call is on it.

Can anyone explain? I couldn’t find any resources about this inherent Trait methods anywhere.


#2

Trait objects like &Trait can’t call generic methods like is<T>, because the vtable would need individual function pointers for all possible T!

edit: this may not be the whole story, because a non-object fn foo<T: Trait>(x: &T) also can’t call x.is::<i32>().


#3

is isn’t in the vtable though. It’s an inherent method of the Trait object.


#4

Before you could consider having Any::is be automatically promoted to Trait::is , you’d need some way to coerce an &Trait to an &Any. Try it, it just doesn’t work. Absent that coercion, there’s no way you could call Any::is with an &Trait argument, so there’s no way that Trait::is could be implemented in terms of Any::is. There’s an open issue for adding this kind of coercion to the language, but it hasn’t really been touched for a while (note the wonky ancient syntax in the original issue).


#5

Ah, thanks, I missed that detail.


#6

Thanks. I’ve decided to add a as_any method to the trait and implement it for all types via a macro.


#8

You don’t need a macro. You can do it if you use a helper trait:

https://play.rust-lang.org/?gist=ed4f9bdfe7d87e4069d8a1c39c020c38&version=stable&mode=debug

trait AsAny {
    fn as_any(&self) -> &Any;
}

impl<T> AsAny for T
where
    T: Sized + 'static,
{
    fn as_any(&self) -> &Any { self }
}

trait Trait: AsAny {}

#9

That’s great. I’ll use that. Thanks a lot.

I have one more question: Using Self: Sized on the Trait would fix the problem but using that makes it unable to make the trait into a trait object. It seems counter-intuitive to me as unsized objects cannot be made into a trait object anyway :confused:


#10

The Trait object type itself (let’s call it dyn Trait) is unsized, and it has to implement Trait. If you had Self: Sized then you couldn’t have dyn Trait: Trait. Technically, it could still work that way, but it was decided that having dyn Trait: Trait only some of the time would be confusing, and it’s definitely desirable that generic methods can work with object types.


#11

You can also consider using the “landing pad” approach: Inherited Traits / Implementations (Methods)?