# Draft RFC: default types for traits

**URL:** <https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948>\
**Category:** Uncategorized\
**Created:** [December 3, 2018, 10:22am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948 "2018-12-03T10:22:58Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [December 3, 2018, 10:22am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/1 "2018-12-03T10:22:58Z")

</div>

[Click here for that RFC goodness.](https://github.com/canndrew/rfcs/blob/default-types/text/0000-default-types.md)

This idea came out of the [Never types and inference](https://internals.rust-lang.org/t/never-types-and-inference/8924) thread and [an earlier RFCs issue](https://github.com/rust-lang/rfcs/issues/2211).

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [December 3, 2018, 3:45pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/2 "2018-12-03T15:45:09Z")

</div>

From the RFC text:

> It would probably be quite a perverse use of the `Default` trait if calling `default()` then immediately dropping the resulting value intentionally caused IO or something.

Ouch. First of all, since `Default::default()` isn't `const`, this is allowed, however "perverse" one imagines it to be. Therefore, assuming it's not the case would be **incorrect.**

But it doesn't need to be a "perverse" thing either. A perfectly fine use case is a default-constructed RAII guard, for example. That would be impossible to rely on if this RFC was realized.

(For these reasons, it should be obvious, but I strongly oppose this RFC.)

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [December 3, 2018, 4:03pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/3 "2018-12-03T16:03:51Z")

</div>

> [@H2CO3](#):
>
> But it doesn’t need to be a “perverse” thing either. A perfectly fine use case is a default-constructed RAII guard, for example. That would be impossible to rely on if this RFC was realized.

I don't think this RFC would affect that at all, presumably the closest thing you could write that this RFC almost seems relevant to is:

```rust
let _guard: MyIoPerformingGuard = Default::default();

```

(although, I don't know why you wouldn't explicitly use `MyIoPerformingGuard::default()`). In that case this RFC wouldn't affect what is happening because inference will select `<MyIoPerformingGuard as Default>::default()`. This RFC is _only_ for those cases where inference is otherwise unconstrained and has no idea what to do, i.e. those cases that currently error out with:

```rust
error[E0282]: type annotations needed
 --> src/main.rs:2:9
  |
2 | let x = Default::default();    
  | ^
  | |
  | cannot infer type
  | consider giving `x` a type

```

(at least, this is my understanding of the RFC, re-reading I don't see it being very explicitly laid out in the text so it may be that my preconceptions of where this feature could be useful are be colouring my understanding).

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [December 3, 2018, 6:03pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/4 "2018-12-03T18:03:58Z")

</div>

> > ```rust
> > let vals = my_iter.into_iter().map(|(_a, b)| b).collect(); 
> > ... 
> > for val in vals { ... }
> > 
> > ```
> 
> In this code the type of `vals` has not been specified, all that we know is that it is required to implement `Default + Extend<B> + IntoIterator<Item = B>` . The canonical type which satisfies these constraints is, arguably, `Vec<B>` .

We know that it implements `FromIterator<Item=B>` due to `collect` and `IntoIterator` due to `for _ in vals`. The comment from which this was adapted had defined its own function and trait bounds. However, choosing `Vec<_>` as the canonical type for the combination would be disputable in both versions:

- Consider the case where `B = Result<(), Error>`. Then `collect::<Result<(), _>>` would lead to correctly typed code, with no dynamic allocation. Not erroring potentially hides a programming error, even changing the semantics of `collect` completely, as one terminates early while the other forcibly consumes all elements.

- Should `Vec<_>` be chosen as the canonical trait instantiation even when `IntoIterator` is not given? If not, then adding more trait bounds could both lead to more or less type deduction, depending on the set of non-explicit and invisble bounds inferred from code. That does not make a compelling case for consistent reasoning. But on the opposite, if so, should it be guaranteed that adding a new bound that `Vec<_>` satisfies still results in `Vec<_>` being selected? I feel like yes, that's how other type deduction rules work, they can't fail if you add more already satisfied bounds. The RFC should at least suggest or discuss ways how to check that, I think.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [December 3, 2018, 7:55pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/5 "2018-12-03T19:55:48Z")

</div>

I'd definitely like to solve the `unimplemented!()` problem for futures!

> ```rust
> default<T> IntoIterator<T> = NeverOutput<T>;
> default<T> Default + Extend<T> + IntoIterator<T> = Vec<T>;
> 
> ```

How does semver work for these? If the first one existed, would it mean we could never add the latter, as it would change types?

Also, there should probably be a coherence note. The obvious thing there is that only the crate defining the trait can default the trait, but that will be trouble for things like `IntoIterator` that are in `core`, as it cannot mention `Vec`.

---

<div class="post-metadata">

**Author:** ![derekdreery](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/derekdreery/32/2632_2.png) [@derekdreery](https://internals.rust-lang.org/u/derekdreery)\
**Post date:** [December 4, 2018, 3:14pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/6 "2018-12-04T15:14:41Z")

</div>

Could the RFC be broken down into stages:

> - Try to default to `!` in all situations rather than just some as Rust does today.

Could we do this first, evaluate how it works in practice, then use that to inform the debate on other parts of this proposal. I think the above would be less controversial since there is no new syntax, it just means some valid programs pass that would have failed before. I don't know how this relates to async functions as I haven't really been following the discussion there.

I think that there are real improvements to be had in ergonomics with this RFC, or another similar one, and I think this RFC is an important addition to the debate. It would be nice to avoid new syntax though, and I havn't thought enough about the consequences of this - does it simplify code or make it more complicated by introducing "compiler magic". I think simplifies, since taking the example

```rust
fn gen_error() -> impl Error {
    unimplemented!();
}

```

I think it's reasonable to accept this program (if we have `impl Error for !`), since the return type of the function body is `!`. Also I don't think it gets counter-intuitive if we increase complexity

```rust
fn construct_ok<T, E>(val: T) -> Result<T, E> {
  Ok(val)
}

```

However in this case I think it would be clearer written like

```rust
fn construct_ok<T>(val: T) -> Result<T, !> {
  Ok(val)
}

```

. We would then need ! to coerce into any other type - I don't know if that is part of the never proposal.

---

<div class="post-metadata">

**Author:** ![joelgallant](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joelgallant/32/9490_2.png) [@joelgallant](https://internals.rust-lang.org/u/joelgallant)\
**Post date:** [December 4, 2018, 7:40pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/7 "2018-12-04T19:40:34Z")

</div>

This is just my 2 cents as somebody new-ish to writing rust full time, but I’m highly in favor of something that would fix the `-> impl Future { unimplemented!(); }` problem. I’ve run in to it way more than I would have thought (I’m a heavy user of `impl`, I find it really nice). I can’t comment much on this rfc, but I like that specific papercut that it solves.

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [December 6, 2018, 6:47am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/8 "2018-12-06T06:47:34Z")

</div>

> [@H2CO3](#):
>
> Ouch. First of all, since `Default::default()` isn’t `const` , this is allowed, however “perverse” one imagines it to be. Therefore, assuming it’s not the case would be **incorrect.**
> 
> But it doesn’t need to be a “perverse” thing either. A perfectly fine use case is a default-constructed RAII guard, for example. That would be impossible to rely on if this RFC was realized.

Can you give an example of an RAII guard that would be created using `Default::default()`? I mean, hypothetically someone might do this but I think @Nemo157 is right in pointing out that it would be weird to not at least write `MyIoPerformingGuard::default()` (or more likely `MyIoPerformingGuard::new(and_probably_some_argument_that_says_what_we_are_guarding)`)

Nonetheless, I'll concede that including `default Default = ()` might be a bad idea - at least if it got used without raising a warning - though I think in practice it would be unlikely to cause problems.

> [@197g](#):
>
> Should `Vec<_>` be chosen as the canonical trait instantiation even when `IntoIterator` is not given?

I would say definitely not. If we only have a bound of `FromIterator<B>` and not `IntoIterator<Item = B>` then the type we need is one that collects values but never hands them back. `()` might make sense in this case if it implemented `FromIterator<B>`, although it's not clear whether the code expects the iterator to be drained or not (which is why `()` doesn't implement `FromIterator<Item = B>`). Once you add the `IntoIterator<Item = B>` bound though, you now need a type which consumes a sequence of `B`s and then produces a sequence of `B`s.

> [@scottmcm](#):
>
> How does semver work for these? If the first one existed, would it mean we could never add the latter, as it would change types?

That's a good point, though in this case `NeverOutput<T>` doesn't implement `Default` so it would be fine. Maybe @197g is right and we shouldn't be able to override less-specific default type declarations with more specific ones.

> [@joelgallant](#):
>
> This is just my 2 cents as somebody new-ish to writing rust full time, but I’m highly in favor of something that would fix the `-> impl Future { unimplemented!(); }` problem.

Yeah that is one of the main motivations of the RFC. An alternative solution would be if we somehow had `!: Future<Output = T>` for all `T`. Perhaps `!` should be more magical and automatically implement (almost) all traits. Or perhaps there should be a way of writing trait impls which turn associated types into generic type arguments, something like:

```rust
// T not used on Future or !, just on the associated type.
impl<T> Future for ! {
    type Output = T;
    ...
}

```

Writing `<! as Future>::Output` would then produce a type variable, unifiable with anything. I don't know whether this completely breaks the type system though.

---

<div class="post-metadata">

**Author:** ![Riateche](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/riateche/32/1717_2.png) [@Riateche](https://internals.rust-lang.org/u/Riateche)\
**Post date:** [December 6, 2018, 5:05pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/9 "2018-12-06T17:05:31Z")

</div>

If the code doesn’t care about the concrete type, why would you want to specify a concrete type? In this example you provided, why choose `Vec<T>` over anything else?

```rust
default<T> Default + Extend<T> + IntoIterator<T> = Vec<T>;

```

Consider the following alternative. When a compiler encounters an `impl Trait` type that cannot be resolved and if the compiler can prove that no trait methods will ever be called for that type, it can just generate a concrete type like this:

```rust
struct Unused;
struct Unused2;

impl Future for Unused {
    type Item = u32;
    type Error = Unused2;

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        unsafe { unreachable_unchecked() }
    }
}

// return type resolves to `Unused`
fn make_future() -> impl Future<Output = u32> {
    unimplemented!()
}

```

This completely eliminates the need for any manual defaults management.

This won’t work in cases where the trait methods are actually called (like in the `default()` example), but that’s a questionable use case because it’s unclear how the author of the calling code can figure out which implementation is called.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [December 6, 2018, 6:42pm UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/10 "2018-12-06T18:42:49Z")

</div>

> [@canndrew](#):
>
> Can you give an example of an RAII guard that would be created using `Default::default()`

Not off the top of my head, but again, that doesn't mean the compiler should be free to assume constraints which are not encoded in the type system but which are instead only based on loose conventions of "plausibility". (I can imagine, for example, how this might silently break existing assumptions about unsafe code, which may have catastrophic results.)

> [@Riateche](#):
>
> it’s unclear how the author of the calling code can figure out which implementation is called.

Indeed – agreed, and this probably highlights an even more worrying issue. Second guessing the user is not a nice thing to do in any context. If the compiler can't decide what to do, why doesn't it just issue a diagnostic? Resolving ambiguity in a 100% automatic _and_ correct way (I _don't_ just mean "it typechecks" but "it's doing what the programmer _really_ wanted it to do") is probably infeasible.

I just have a hard time believing that the trade-off of eliminating the rare annoyance associated with having to come up with a dummy type is worth the price of potentially doing something completely incorrect or at least dodgy, worse yet doing it _silently._

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [December 7, 2018, 3:43am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/11 "2018-12-07T03:43:57Z")

</div>

> [@Riateche](#):
>
> Consider the following alternative. When a compiler encounters an `impl Trait` type that cannot be resolved and if the compiler can prove that no trait methods will ever be called for that type, it can just generate a concrete type like this:

That's basically what defaulting to `!` is. Except that `!` can't implement `Future<Output = T>` so the RFC proposes the `NeverOutput<T>` type on top of that.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [December 7, 2018, 4:29am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/12 "2018-12-07T04:29:10Z")

</div>

> [@Riateche](#):
>
> ```rust
> fn make_future() -> impl Future<Output = u32> {
> unimplemented!()
> }
> 
> ```

Thinking about this again, this is solved by async/await, right?

```rust
async fn make_future() -> u32 {
    unimplemented!()
}

```

(Though that does move the panic to the first `poll`, iirc)

Are there other examples where the fallback really needs to be on the trait? (As opposed to `collect`-style ones where putting it on the method would be reasonable.)

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [December 7, 2018, 5:05am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/13 "2018-12-07T05:05:28Z")

</div>

> [@scottmcm](#):
>
> Are there other examples where the fallback really needs to be on the trait? (As opposed to `collect` -style ones where putting it on the method would be reasonable.)

How about?

```rust
fn make_iterator() -> impl Iterator<Item = u32> {
    unimplemented!()
}

```

---

<div class="post-metadata">

**Author:** ![Riateche](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/riateche/32/1717_2.png) [@Riateche](https://internals.rust-lang.org/u/Riateche)\
**Post date:** [December 7, 2018, 8:12am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/14 "2018-12-07T08:12:08Z")

</div>

> [@canndrew](#):
>
> That’s basically what defaulting to `!` is. Except that `!` can’t implement `Future<Output = T>` so the RFC proposes the `NeverOutput<T>` type on top of that.

But the compiler can automatically generate an `Unused<T>` that will implement `Future<Output = T>`, so it should work. What's the benefit of designing a dedicated `NeverOutput` type for this purpose (and manually assigning it as the default for a potentially huge number of traits) over just automatically generating a struct on demand?

---

<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:** [March 25, 2019, 8:31am UTC](https://internals.rust-lang.org/t/draft-rfc-default-types-for-traits/8948/15 "2019-03-25T08:31:15Z")

</div>

Closed on March 25, 2019, 8:31am UTC

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