# Idea: make object-safe subset of \`dyn Trait\` methods available as inherent methods

**URL:** <https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266>\
**Category:** Uncategorized\
**Created:** [November 10, 2019, 12:38am UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266 "2019-11-10T00:38:44Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mikeyhew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mikeyhew/32/2270_2.png) [@mikeyhew](https://internals.rust-lang.org/u/mikeyhew)\
**Post date:** [November 10, 2019, 12:38am UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266/1 "2019-11-10T00:38:44Z")

</div>

I got a brain wave today when I was reading [this blog post](https://gankra.github.io/blah/swift-abi/), which briefly mentioned object safety in Rust and how Swift avoids that issue. Now that [RFC 2027](https://github.com/rust-lang/rfcs/blob/master/text/2027-object_safe_for_dispatch.md) has been implemented, if you enable the feature `object_safe_for_dispatch`, `dyn Trait` is always a well-formed type, it just doesn't implement `Trait` if the trait isn't object-safe. Being object-safe really just means that the `dyn Trait` type can't implement `Trait`, because of one of the following reasons:

- the trait requires `Self: Sized`, which `dyn Trait` inherently is not,
- the trait has an associated `const`, which `dyn Trait` couldn't provide a value for, or
- the trait has one or more methods/associated functions that can't be implemented using dynamic dispatch. For example, there is no `self` argument, and therefore no vtable to do dynamic dispatch on; or the method returns `Self`; or one of a few other reasons.

There might be another reason that I'm missing, but the main thing to notice here is that there might be some methods that can definitely be implemented using dynamic dispatch, even if the trait as a whole cannot. What if we took the subset of methods that are object-safe, and made them available as inherent methods?

Take for example this trait:

```rust
trait Trait {
    // not object safe, because it has no `self` argument
    fn static_method();
    // this method is fine
    fn call_static_method(&self) {
        Self::static_method()
    }
}

```

`dyn Trait` can't provide an implementation of `static_method`, and therefore can't implement `Trait`. But it could still provide `call_static_method` as an inherent method. It would be like the following code was added:

```rust
impl dyn Trait {
    fn call_static_method(&self) {
        /* compiler implemented */
    }
}

```

Then you could do this, assuming `i32` implements `Trait`:

```rust
let bx = Box::new(6) as Box<dyn Trait>;
bx.call_static_method();

```

Note that the cast to `Box<dyn Trait>` isn't allowed right now, even with `#![feature(object_safe_for_dispatch)]`. I don't see any reason why you couldn't or shouldn't be able to do that though.

`call_static_method` would be an inherent method on `dyn Trait`, as well as on any `dyn SubTrait` types where `SubTrait` requires `Self: Trait`. There's one complication I just thought of, though: what if `SubTrait` also has a method named `call_static_method`? Normally, you would disambiguate the two with `<dyn SubTrait as Trait>::call_static_method` and `<dyn SubTrait as SubTrait>::call_static_method`, but that doesn't work if they are both inherent methods on `dyn SubTrait`. I guess it's an open question what to in that case.

What do you think? Are there any other complications that I'm missing?

cc @withoutboats @arielb1 @eddyb @nikomatsakis

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [November 10, 2019, 5:56am UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266/2 "2019-11-10T05:56:42Z")

</div>

With specialization this could even be implemented with a `proc_macro_attribute` on the trait:

```rust
#[derive_with_receiver_static_methods(template = "call_{}")]
trait Trait {
    fn static_method ()
    where
        Self : Sized,
    ;
}

```

would expand to:

```rust
trait Trait {
    fn static_method ()
    where
        Self : Sized,
    ;

    fn call_static_method (self: &'_ Self)
    ;
}

default impl<T> Trait for T {
    #[inline]
    fn call_static_method (self: &'_ Self)
    {
        Self::static_method()
    }
}

```

And if one does not want to pollute the namespace of `Trait`, something along the following lines could be implemented by the compiler:

```rust
#![feature(specialization)]

trait Trait {
    fn static_method ()
    where
        Self : Sized,
    ;
    
    #[doc(hidden)]
    #[allow(bad_style)]
    fn __vtable__ call_static_method (self: &'_ Self)
    ;
}

default impl<T> Trait for T {
    fn __vtable__ call_static_method (self: &'_ Self)
    {
        <Self as Trait>::static_method()
    }
}

impl dyn Trait + '_ {
    #[inline]
    fn static_method (self: &'_ Self)
    {
        <Self as Trait>:: __vtable__ call_static_method(self)
    }
}

```

- [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=653d10ddc5ec81365b4bddbe06ea7ea1)

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [November 10, 2019, 2:29pm UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266/3 "2019-11-10T14:29:56Z")

</div>

> [@mikeyhew](#):
>
> There might be another reason that I'm missing, but the main thing to notice here is that there might be some methods that can definitely be implemented using dynamic dispatch, even if the trait as a whole cannot. What if we took the subset of methods that are object-safe, and made them available as inherent methods?

It sounds like you're describing Rust's pre-[RFC 255](https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md) behavior.

---

<div class="post-metadata">

**Author:** ![mikeyhew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mikeyhew/32/2270_2.png) [@mikeyhew](https://internals.rust-lang.org/u/mikeyhew)\
**Post date:** [November 11, 2019, 6:03am UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266/4 "2019-11-11T06:03:59Z")

</div>

> [@bascule](#):
>
> It sounds like you're describing Rust's pre-[RFC 255](https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md) behavior.

_Interesting..._ it would be nice to hear what @nrc, the RFC author, thinks, and anyone else who was around at that time.

Actually, take a look at this paragraph in the alternatives section:

> [@](#):
>
> We could continue to check methods rather than traits are object-safe. When checking the bounds of a type parameter for a function call where the function is called with a trait object, we would check that all methods are object-safe as part of the check that the actual type parameter satisfies the formal bounds. We could probably give a different error message if the bounds are met, but the trait is not object-safe.

This is pretty much exactly what I'm proposing we do.

---

<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:** [February 9, 2020, 6:03am UTC](https://internals.rust-lang.org/t/idea-make-object-safe-subset-of-dyn-trait-methods-available-as-inherent-methods/11266/5 "2020-02-09T06:03:59Z")

</div>

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