Rust impl Trait For Programmers
Tags: rust, learning, examples
Published: 2019-01-22 01:22:27


---
title: Rust impl Trait For Programmers
published: true
description: an examples-first, simple and real view of a rust feature
tags: rust, learning, examples
---

![Header](https://thepracticaldev.s3.amazonaws.com/i/65m72cdmjuuor8r8rzqy.png)

# Table of Contents

1.  [Introduction](#orgf424d38)
2.  [Examples](#org450011c)
    1.  [Return impl Trait](#orgd8294b0)
    2.  [Argument impl Trait](#org3916b39)
    3.  [Relationship to dyn/dynamic types](#org361baaa)
3.  [Commentary](#orgcfa2305)
    1.  [Argument position controversy](#org3776596)
    2.  [Future of impl Trait](#org1445a82)
    3.  [Where's the type theory?](#org8c880cb)
    4.  [Applied example (return position)](#org642d739)


<a id="orgf424d38"></a>

# Introduction

Rust's `impl Trait` is a little useful.

`impl Trait` gives the ability to hide types in functions. It is best in `-> return` position, but is also usable in `(argument)` position.

Use it when you know what Trait you want something for, but you don't care what it really is.


<a id="org450011c"></a>

# Examples


<a id="orgd8294b0"></a>

## Return impl Trait

Here it is:
```rust
    use std::fmt::Display;
    
    // First case: compiler wants more
    fn <T: Display>does_not_work() -> T {"Whoops!"}
    // Second case: compiler satisfied
    fn actually_works() -> impl Display {"Not whoops!"}
```
Without impl Trait, it looks like this:
```rust
    fn old_explicit_way_that_works() -> String {"Duh"}
    fn slow_way_that_works() -> Box<dyn Display> {Box::new("Hello")}
```
Sometimes, the old way requires you to write a big, awful type that has nothing to do with how it is actually used. This solves that.


<a id="org3916b39"></a>

## Argument impl Trait

The following two things are almost identical:
```rust
    fn visible_type_parameter<T: Trait>(x: T) {}
    fn hidden_type_parameter(x: impl T) {}
```
It is sometimes helpful to specify T using `turbofish_aka_explicit_type::<DesiredType>`. This is not currntly possible with `impl T`. Don't overthink this one; I favor type parameters. See commentary for a debate.


<a id="org361baaa"></a>

## Relationship to dyn/dynamic types

Runtime Trait objects specified by `&'lifetime dyn Trait` or `Box<dyn Trait>` can be converted to compile time types. This is a conversion from dynamic to static typing.
```rust
    trait Trait {}
    struct Type;
    impl Trait for Type {}
    
    fn dynamic_type(x: &dyn Trait) {}
    
    fn static_explicit_type(x: &Type) {}
    fn static_implicit_hidden_type(x: &impl Trait) {}
    fn static_implicit_visible_type<T: Trait>(x: &T) {}
    
    fn main() {
        let x = Type;
        dynamic_type(&x as &Type);
        static_explicit_type(&x);
        static_implicit_hidden_type(&x);
    //    static_implicit_hidden_type::<Type>(&x); doesn't work (yet?)
        static_implicit_visible_type(&x);
        static_implicit_visible_type::<Type>(&x);
    }
```
This only works when `&dyn Trait` refers to a single type; i.e. you can only return one type from one function.


<a id="orgcfa2305"></a>

# Commentary


<a id="org3776596"></a>

## Argument position controversy

<https://github.com/rust-lang/rfcs/pull/2444>
I can't summarize this issue easily. Read for yourself, especially the last post, to get a sense.   


<a id="org1445a82"></a>

## Future of impl Trait

Official tracking issue:
<https://github.com/rust-lang/rust/issues/34511>
It's January 2019. Here's what I see:

-   Existential types (aka `type x = impl Trait` but in a way that makes sense)
-   `impl X + Y` for multiple traits.
-   Various other things to make it more complete.
-   Potential that `::<Turbofish>` will appear a la "synthetic" type parameters. <https://github.com/rust-lang/rust/issues/44721#issuecomment-330945507>


<a id="org8c880cb"></a>

## Where's the type theory?

People have tried to explain it this way (existential? universal?), but take a step back to look at rust. `impl Trait` is a single step forward in type inference.

Recognize that I'm not using a powerful set of tools for understanding type systems that does exist. Give this article a read:
<https://varkor.github.io/blog/2018/07/03/existential-types-in-rust.html>


<a id="org642d739"></a>

## Applied example (return position)

Naive attempt:
```rust
    use std::fmt::Display;
    
    fn main() {
        println!("{}", make_value(0));
        println!("{}", make_value(1));
    }
    
    fn make_value<T: Display>(index: usize) -> T {
        match index {
            0 => "Hello, World",
            1 => "Hello, World (1)",
            _ => panic!(),
        }
    }
```
Fails because&#x2026;
```
    error[E0282]: type annotations needed
     --> /home/sam/code/trash/impl-return.rs:4:20
      |
    4 |     println!("{}", make_value(0));
      |                    ^^^^^^^^^^ cannot infer type for `T`
    
    error[E0308]: match arms have incompatible types
      --> /home/sam/code/trash/impl-return.rs:9:5
       |
    9  | /     match index {
    10 | |         0 => "Hello, World",
       | |              -------------- match arm with an incompatible type
    11 | |         1 => "Hello, World (1)",
    12 | |         _ => panic!(),
    13 | |     }
       | |_____^ expected type parameter, found reference
       |
       = note: expected type `T`
                  found type `&'static str`
    
    error: aborting due to 2 previous errors
    
    Some errors occurred: E0282, E0308.
    For more information about an error, try `rustc --explain E0282`.
```
Okay, so I do this:
```rust
    use std::fmt::Display;
    
    fn main() {
        println!("{}", make_value::<&'static str>(0));
        println!("{}", make_value::<&'static str>(1));
    }
    
    fn make_value<T: Display>(index: usize) -> T {
        match index {
            0 => "Hello, World",
            1 => "okay",
            _ => panic!(),
        }
    }
```
Another dead end:
```
    error[E0308]: match arms have incompatible types
      --> /home/sam/code/trash/impl-return.rs:9:5
       |
    9  | /     match index {
    10 | |         0 => "Hello, World",
       | |              -------------- match arm with an incompatible type
    11 | |         1 => "okay",
    12 | |         _ => panic!(),
    13 | |     }
       | |_____^ expected type parameter, found reference
       |
       = note: expected type `T`
                  found type `&'static str`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0308`.
```
Yet this succeeds:
```rust
    use std::fmt::Display;
    
    fn make_value(index: usize) -> impl Display {
        match index {
            0 => "Hello, World",
            1 => "Hello, World (1)",
            _ => panic!(),
        }
    }
```

(Generated using org-mode)