# Pre-RFC: AsDynRef and AsDynMut

**URL:** <https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988>\
**Category:** language design\
**Created:** [March 16, 2020, 4:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988 "2020-03-16T16:59:04Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [March 16, 2020, 4:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/1 "2020-03-16T16:59:05Z")

</div>

Please tell me what you think!

## Summary

These traits allow converting any object to a trait object. Specifically,

- `AsDynRef` converts `&T` to `&dyn SomeTrait` where `T: SomeTrait`
- `AsDynMut` converts `&mut T` to `&mut dyn SomeTrait` where `T: SomeTrait`

## Motivation

I recently read a [blog post](https://llogiq.github.io/2020/03/14/ootb.html) explaining how to create a trait object whose concrete type is unknown at compile time. The optimal solution turns out to be complicated and non-obvious.

This proposal tries to change that; it allows us to implement the `AsDynRef` and `AsDynMut` traits for **wrapper types**. For example, we can implement them for an enum with two variants:

```rust
enum Either<L, R> {
    Left(L),
    Right(R),
}

impl<'a, A, B, TraitObj> AsDynMut<'a, TraitObj> for Either<A, B>
where
    A: AsDynMut<'a, TraitObj>,
    B: AsDynMut<'a, TraitObj>,
    TraitObj: ?Sized + 'a,
{
    fn as_dyn_mut(&'a mut self) -> &'a mut TraitObj {
        match self {
            Either::Left(l) => l.as_dyn_mut(),
            Either::Right(r) => r.as_dyn_mut(),
        }
    }
}

```

This gives us a nice way to create a trait object, without knowing the concrete type at compile time:

```rust
let mut readable = if some_condition {
    Either::Left(stdin())
} else {
    Either::Right(File::open(path)?)
};

accepts_read_trait_object(readable.as_dyn_mut());

```

## Guide-level explanation

The traits are defined like this:

```rust
pub trait AsDynRef<'a, TraitObj: ?Sized + 'a>: Sized {
    fn as_dyn_ref(&'a self) -> &'a TraitObj;
}

pub trait AsDynMut<'a, TraitObj: ?Sized + 'a>: Sized {
    fn as_dyn_mut(&'a mut self) -> &'a mut TraitObj;
}

```

These traits are _automatically_ implemented for all types, for all traits they implement, if they're object safe.

An example how they would be implemented for types that implement `Read`:

```rust
impl<'a, T: Read> AsDynRef<'a, dyn Read + 'a> for T {
    fn as_dyn_ref(&'a self) -> &'a (dyn Read + 'a) {
        self
    }
}

impl<'a, T: Read> AsDynMut<'a, dyn Read + 'a> for T {
    fn as_dyn_mut(&'a mut self) -> &'a mut (dyn Read + 'a) {
        self
    }
}

```

Since there is currently no mechanism to implement these traits for all trait objects, they have to be built into the compiler.

## Drawbacks

This adds two more built-in traits, making the language more complicated.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [March 18, 2020, 2:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/2 "2020-03-18T14:57:06Z")

</div>

> [@Aloso](#):
>
> ```rust
> impl<'a, A, B, TraitObj> AsDynMut<'a, TraitObj> for Either<A, B>
> 
> ```

How are you going to resolve the conflicting implementation when we `impl TraitObj for Either<A, B>`?

* * *

And if you don't use a trait, this feature already exists via the (unstable) [`Unsize` marker trait](https://doc.rust-lang.org/std/marker/trait.Unsize.html).

```rust
#![feature(unsize)]
use std::marker::Unsize;

pub enum Either<L, R> {
    Left(L),
    Right(R)
}
impl<L, R> Either<L, R> {
    fn as_dyn_ref<U>(&self) -> &U 
    where 
        U: ?Sized,
        L: Unsize<U>,
        R: Unsize<U>,
    {
        match self {
            Either::Left(a) => a,
            Either::Right(b) => b,
        }
    }
}

fn main() {
    for i in 0..2 {
        let f = if i == 0 {
            Either::Left(|x| x + 1)
        } else {
            Either::Right(|x| x - 1)
        };
        
        let g = f.as_dyn_ref::<dyn Fn(i32) -> i32>();
        dbg!(g(5));
        // expected output:
        // g(5) = 6
        // g(5) = 4
    }
}

```

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [March 19, 2020, 1:29am UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/3 "2020-03-19T01:29:27Z")

</div>

> [@kennytm](#):
>
> How are you going to resolve the conflicting implementation when we `impl TraitObj for Either<A, B>` ?

We don't need to implement `TraitObj`, that's just a type variable. However, it's perfectly fine to implement `AsDynRef` or `AsDynMut` for a type multiple times. For example, a type can implement both `AsDynMut<dyn Read>` and `AsDynMut<dyn Write>`. There's no conflict.

> [@kennytm](#):
>
> And if you don't use a trait, this feature already exists via the (unstable) [`Unsize` marker trait](https://doc.rust-lang.org/std/marker/trait.Unsize.html).

Wow, I wasn't aware of that!

P.S. if you use the `either` crate, you don't have to implement anything for `Either<L, R>`, because it implements `Deref(Mut)` for all traits implemented by both `L` and `R`. So if both variants implement `AsDynMut`, you can call `.as_dyn_mut()` on `Either`.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [March 19, 2020, 5:39am UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/4 "2020-03-19T05:39:23Z")

</div>

> [@Aloso](#):
>
> We don't need to implement `TraitObj` , that's just a type variable. However, it's perfectly fine to implement `AsDynRef` or `AsDynMut` for a type multiple times. For example, a type can implement both `AsDynMut<dyn Read>` and `AsDynMut<dyn Write>` . There's no conflict

What I mean is if we `impl Read for Either`, then the custom `impl<U> AsDynRef<U> for Either` will conflict with the generated `impl AsDynRef<dyn Read> for Either`.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [March 19, 2020, 2:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/5 "2020-03-19T14:27:57Z")

</div>

I think you misunderstood me. If the traits are auto-implemented, we don't need to implement them for anything explicitly.

However, since you told me that the `Unsize` trait can do something similar, I don't think they're necessary anyway 🙂

---

<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:** [June 17, 2020, 2:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-asdynref-and-asdynmut/11988/6 "2020-06-17T14:36:11Z")

</div>

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