# Suggestion for making Rust's trait system more usable for generics

**URL:** <https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155>\
**Category:** community\
**Created:** [November 26, 2019, 8:51pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155 "2019-11-26T20:51:51Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![osrust](https://avatars.discourse-cdn.com/v4/letter/o/ee7513/32.png) [@osrust](https://users.rust-lang.org/u/osrust)\
**Post date:** [November 28, 2019, 12:38pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/42 "2019-11-28T12:38:39Z")

</div>

> A language empowering everyone to build reliable and efficient software.

It's a generic statement and not related to (I'd suppose) targeting.

---

<div class="post-metadata">

**Author:** ![ZiCog](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/zicog/32/12216_2.png) [@ZiCog](https://users.rust-lang.org/u/ZiCog)\
**Post date:** [November 28, 2019, 1:23pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/43 "2019-11-28T13:23:07Z")

</div>

> [@osrust](#):
>
> It's a generic statement and not related to (I'd suppose) targeting.

Perhaps sounds like a generic marketing blurb.

But unlike such fluff it is strangely very specific. It is a concise and precise statement of the purpose of Rust.

I wonder now what you mean by "targeting". What was the target market for C++ when Bjarne dreamed it up? C++ is everywhere, from Arduino playthings to high speed trading at financial institutions. Most application areas of C++ today were not even on the radar at the time.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/rustyyato/32/49247_2.png) [@RustyYato](https://users.rust-lang.org/u/RustyYato)\
**Post date:** [November 29, 2019, 2:32am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/44 "2019-11-29T02:32:58Z")

</div>

> [@Rust 2020: Growth](https://users.rust-lang.org/t/rust-2020-growth/34956/102):
>
> fn gen\<H: HashMap\<u32, f32\>::Trait\>(m: H) -\> f32 { ... }

This is basically what I put before. You said that this wasn't what you wanted.

> [@Rust 2020: Growth](https://users.rust-lang.org/t/rust-2020-growth/34956/98):
>
> This can't be used with your proposal, it would have to be
> 
> ```rust
> fn foo<H: HashMap<u32, f32>>(h: H) -> f32 { ... }
> 
> ```

But I think we were just talking past each other. In any case, I wouldn't want this level of generics for a normal api. It makes it much harder to implement and harder to learn.

> [@Rust 2020: Growth](https://users.rust-lang.org/t/rust-2020-growth/34956/102):
>
> And in the generic case it is already today possible that the trait implementation does not adhere to the semantic requirements of the trait, and unsound implementations are probably pretty common.

Yes, that's why I don't want this to be implicit.

> [@Rust 2020: Growth](https://users.rust-lang.org/t/rust-2020-growth/34956/102):
>
> Basically one could code only using traits and compose new traits from other traits

Yes, and this is how things work right now. One thing I really like about traits is that they _only_ model behaviors. This makes them really easy to compose, because it is relatively easy to reason about behaviors.

> [@Rust 2020: Growth](https://users.rust-lang.org/t/rust-2020-growth/34956/102):
>
> I was hoping there were people here who share the same views. However it seems to be the trend that "object oriented Programming" (which doesn't describe much to be honest) is too mainstream and responsible for a lot of problems in the programming world.

In this thread at least, it doesn't look like people are complaining about object oriented programming, as much as inheritance. There are some very specific assertions, such as inheritance makes code harder to reason about, and harder to maintain. Rust does support some forms of inheritance, but it is very limited, structured, and for a specific purpose (traits).

---

<div class="post-metadata">

**Author:** ![mankinskin](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mankinskin/32/46764_2.png) [@mankinskin](https://users.rust-lang.org/u/mankinskin)\
**Post date:** [November 29, 2019, 2:51am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/45 "2019-11-29T02:51:07Z")

</div>

> [@RustyYato](#):
>
> This is basically what I put before. You said that this wasn't what you wanted.

Yes, because you said this generic implementation would also be required to use `HashMap<u32, f32>` with `foo`, which is not what I just wrote. The type parameter is only required if you want to use any type that implements `HashMap<u32, f32>::Trait` with `foo`.

> [@RustyYato](#):
>
> Yes, that's why I don't want this to be implicit.

Aha, I think this is where our fundamental misunderstanding stems from. I am thinking _the more traits, the better_, because you can use more generic functions.  
But you are seeing that traits are opportunities for semantic misbehavior and also they make API comprehension more difficult.

I am not exactly agreeing that generic APIs are harder to understand, as I usually assume that the interfaces are well-defined, and then everything is quite transparent. But obviously this is a false assumption, as trait implementations could fail given unit tests.

I am generally thinking a lot about how to make a language generic and still unambiguously defined and correct. Using type systems you can definitely narrow down possible values for any arguments to a function and could potentially exactly encode the valid domain of the function exactly, and that way you could also encode semantics into the type system, but the closest to a type system like this that I have found was probably haskell, and even there I do not know of any builtin way to limit fundamental types to specific intervals. Although it is an obvious abstraction, especially if you had one or the other math class.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/rustyyato/32/49247_2.png) [@RustyYato](https://users.rust-lang.org/u/RustyYato)\
**Post date:** [November 29, 2019, 3:03am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/46 "2019-11-29T03:03:07Z")

</div>

> [@mankinskin](#):
>
> But you are seeing that traits are opportunities for semantic misbehavior and also they make API comprehension more difficult.

If overused, yes, generics can make very unreadable code. They are also harder to implement correctly.

> [@mankinskin](#):
>
> I am generally thinking a lot about how to make a language generic and still unambiguously defined and correct.

Being "unambiguously defined and correct" for who? The compiler, the person reading the code, the person writing the code?

> [@mankinskin](#):
>
> but the closest to a type system like this that I have found was probably haskell, and even there I do not know of any builtin way to limit fundamental types to specific intervals

Have you looked into dependently typed languages like Idris?

---

<div class="post-metadata">

**Author:** ![mankinskin](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/mankinskin/32/46764_2.png) [@mankinskin](https://users.rust-lang.org/u/mankinskin)\
**Post date:** [November 29, 2019, 3:10am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/47 "2019-11-29T03:10:32Z")

</div>

> [@RustyYato](#):
>
> Being "unambiguously defined and correct" for who? The compiler, the person reading the code, the person writing the code?

unambiguously defined for the compiler (and the reader consequently), correct for the author.

> [@RustyYato](#):
>
> Have you looked into dependently typed languages like Idris?

Not yet but it sounds very interesting to me. Thanks!

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/rustyyato/32/49247_2.png) [@RustyYato](https://users.rust-lang.org/u/RustyYato)\
**Post date:** [November 29, 2019, 3:54am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/48 "2019-11-29T03:54:16Z")

</div>

> [@mankinskin](#):
>
> (and the reader consequently

This is demonstrably not true. Things which are obvious to a computer can be incredibly hard for humans to understand.

---

<div class="post-metadata">

**Author:** ![LarkyRust](https://avatars.discourse-cdn.com/v4/letter/l/f6c823/32.png) [@LarkyRust](https://users.rust-lang.org/u/LarkyRust)\
**Post date:** [November 29, 2019, 7:19am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/49 "2019-11-29T07:19:55Z")

</div>

I am also kind of used to the C++ OOP way, but looks like many modern language sort of gave up the way simultaneously, like Rust and Julia. I believe there is a reason for that, which I am not clear yet.

---

<div class="post-metadata">

**Author:** ![HadrienG](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/hadrieng/32/3798_2.png) [@HadrienG](https://users.rust-lang.org/u/HadrienG)\
**Post date:** [November 29, 2019, 8:29am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/50 "2019-11-29T08:29:35Z")

</div>

I think it basically boils down to C++-style inheritance-based OOP doing simultaneously too much and too little.

- It does too much in the sense that it simultaneously tries to answer concerns of encapsulation, dynamic polymorphism, and implementation reuse with a single abstraction, which becomes complex and hard to use as a result (a bit of it is arguably accidental complexity, though, see Ada as an example of an inheritance-based design that separates those three concerns better)
- It does too little in the sense that it has a hard time answering some concerns that became apparent when trying to apply this style of OOP at a large scale, such as performance loss in hot loops (due to forced allocations, pointer-chasing data model and loss of inlining) and difficulties scaling up and composing across large code bases (due to inheritance being only practical for tree-like hierarchies, with any attempt to generalize it to DAGs with multiple inheritance ending rather badly).

---

<div class="post-metadata">

**Author:** ![ZiCog](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/zicog/32/12216_2.png) [@ZiCog](https://users.rust-lang.org/u/ZiCog)\
**Post date:** [November 29, 2019, 9:05am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/51 "2019-11-29T09:05:34Z")

</div>

> [@LarkyRust](#):
>
> I am also kind of used to the C++ OOP way, but looks like many modern language sort of gave up the way simultaneously, like Rust and Julia. I believe there is a reason for that, which I am not clear yet.

See here:  
Jon Kalb “Back to Basics: Object-Oriented Programming”

[![](https://img.youtube.com/vi/32tDTD9UJCE/maxresdefault.jpg "Back to Basics: Object-Oriented Programming - Jon Kalb - CppCon 2019") ](https://www.youtube.com/watch?v=32tDTD9UJCE&t=1400s)

And all will become clear.

---

<div class="post-metadata">

**Author:** ![Yandros](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/yandros/32/8136_2.png) [@Yandros](https://users.rust-lang.org/u/Yandros)\
**Post date:** [November 29, 2019, 10:05am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/52 "2019-11-29T10:05:24Z")

</div>

> [@zrk](#):
>
> On the topic of inheritance, I find myself missing a delegation mechanism more than "full blown class hierarchies" (that I don't use anymore in C++). Basically, a way of telling the compiler "implement this trait from this field/method" is all I would personally need.

[`::inheritance`](https://docs.rs/inheritance)

---

<div class="post-metadata">

**Author:** ![zrk](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/zrk/32/8172_2.png) [@zrk](https://users.rust-lang.org/u/zrk)\
**Post date:** [November 29, 2019, 9:06pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/53 "2019-11-29T21:06:07Z")

</div>

Yes, like I said in another response, this is similar to what I [attempted last year](https://github.com/dureuill/delegate_test) (except ::inheritance goes the extra mile of actually featuring the proc macro for the delegation part). The need to mark your trait as "delegable" on definition is a blocker though. This is the part that would require language support IMO.

Thanks for releasing this crate, I'm pleased to see work in this direction.

---

<div class="post-metadata">

**Author:** ![crlf0710](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/crlf0710/32/2996_2.png) [@crlf0710](https://users.rust-lang.org/u/crlf0710)\
**Post date:** [November 30, 2019, 11:18am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/54 "2019-11-30T11:18:23Z")

</div>

Rereading [Baby Steps](http://smallcultfollowing.com/babysteps/blog/2015/08/20/virtual-structs-part-3-bringing-enums-and-structs-together/), I wonder how much of this `virtual struct` concept can now be implementable using proc-macros.

While it's not very possible to really bridging the enum and struct concepts together without a touch of the language it self, i think using a composition of enums to show the taxonomy or hierarchy of concepts is do-able. Now we have very powerful tools of proc-macro, this process might not involve a lot of manual work. Many basic things, for example, providing get() /get\_mut() pairs to the shared fields of enum variants can be achieved not too hard, i guess?

I feel that dealing with a single value is not the hardest part of the game, it's dealing with an object graph that's very hard, since the graph will quite possibly be circular, and states are represented as edges within the graph. Some tools like [GitHub - nikomatsakis/mutable: Tinkering with a more ergonomic cell abstraction](https://github.com/nikomatsakis/mutable) presented some interesting steps towards the solution, but it's still not there, i guess.

---

<div class="post-metadata">

**Author:** ![Kobzol](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/kobzol/32/8263_2.png) [@Kobzol](https://users.rust-lang.org/u/Kobzol)\
**Post date:** [December 1, 2019, 9:29am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/55 "2019-12-01T09:29:54Z")

</div>

I have been using [rust-delegate](https://github.com/chancancode/rust-delegate) and for me it seems enough to automate delegation, which is probably the only thing I miss when I don't have inheritance.

---

<div class="post-metadata">

**Author:** ![DevinR528](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/devinr528/32/11650_2.png) [@DevinR528](https://users.rust-lang.org/u/DevinR528)\
**Post date:** [December 1, 2019, 12:32pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/56 "2019-12-01T12:32:58Z")

</div>

Some of the features of OOP can be gained from the `Deref` and `Borrow` traits, the code reuse and type flexibility at least. I think `Deref` especially has a lot of power [auto-ref](https://github.com/dtolnay/case-studies/tree/master/autoref-specialization).

```rust
struct SpecialMap { ... }

impl Deref for SpecialMap {
    fn deref(&self) -> HashMap ...

```

As for the crate authors creating traits for each struct I could see this being helpful but, it's easier for the user of the crate to create traits specifically for bounding generics.

```rust

```

I wonder if the `self/Self` keyword and `impl`'s look too OO and this confuses newcomers because rust looks almost OO you want the same comfy familiar tools but they're just not there. It helped me to remember the `self` stuff is just sugar.

```rust
let mut v = Vec::new();
v.push(10);
// is just 
push(&mut v, 10);

```

---

<div class="post-metadata">

**Author:** ![wthidden](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wthidden/32/10264_2.png) [@wthidden](https://users.rust-lang.org/u/wthidden)\
**Post date:** [December 7, 2019, 3:49pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/57 "2019-12-07T15:49:26Z")

</div>

mankinskin,  
I truly appreciate your enthusiasm for wishing Rust adoption to a wider audience, I too would like to see more adopters. But I fear, as other have pointed out, getting more 'OOP' is not the way to go. And I cringe every time someone says I like 'OOP' because of X. Where in this case X is inheritance, which in general is not OOP. I would implore you too read a few articles by [Alan Kay](https://en.wikipedia.org/wiki/Alan_Kay), or if have some free hours read [The Art of the Metaobject Protocol](https://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744/ref=sr_1_1?crid=2Y3R1G8HUI8RW&keywords=the+art+of+the+metaobject+protocol&qid=1575733613&s=books&sprefix=The+art+of+the+meta%2Cstripbooks%2C139&sr=1-1)

---

<div class="post-metadata">

**Author:** ![tkaitchuck](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/tkaitchuck/32/42191_2.png) [@tkaitchuck](https://users.rust-lang.org/u/tkaitchuck)\
**Post date:** [January 13, 2020, 10:54pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/58 "2020-01-13T22:54:22Z")

</div>

For future readers, these threads may also be helpful: [Inheritance, why is bad?](https://users.rust-lang.org/t/inheritance-why-is-bad/35705) and [How to implement inheritance-like feature for Rust?](https://users.rust-lang.org/t/how-to-implement-inheritance-like-feature-for-rust/31159)

From my point of view (coming from Java) who likes Rust enough to write a book [Rust for Java Developers](https://tkaitchuck.github.io/Rust4JavaDevelopers/), Rust already has the sort of inheritance I would use in Java.

For data types you can do:

```rust
struct A { 
//...
}

struct B {
   a: A,
//...
}

```

and get all the relevant fields. This is sometimes combined with Deref, to unwrap an inner object.  
But that's not common even in Java. Usually in Java, I would have one interface extend another, which you can do with Traits:

```rust
trait FooBar : Foo {
//...
}

```

Traits can also provide a default method just as interfaces do in Java. I would usually use this to implement one method in terms of the others in the interface, that way all the impls get it for free.  
(Copied from Rust by example)

```rust
trait Animal {
    // Instance method signatures; these will return a string.
    fn name(&self) -> &'static str;
    fn noise(&self) -> &'static str;

    // Traits can provide default method definitions.
    fn talk(&self) {
        println!("{} says {}", self.name(), self.noise());
    }
}

```

This can be made even more powerful using Associated types.

However the real power comes when define traits in terms of other traits:

```rust
trait Foo {
   // Some methods I expect others to implement...
}

trait FooExt {
   // Methods I am going to implement...
}

impl<T> FooExt for T where T:Foo {
    // Implementation...
}

```

This way anyone can implement the Foo trait for whatever structure they want, and they will automatically get the implementation of FooExt on their object. This is a very powerful feature that replaces many of the usecases where you might use an abstract class in Java, but it goes further than that because it doesn't force a "child" to have only one "parent". Additionally it allows for much more powerful overloading, where Java Overloads functions based on the function signature, Rust does so based on the Trait, so you don't have to worry about collisions.

The [book I'm putting together](https://tkaitchuck.github.io/Rust4JavaDevelopers/) has some additional details, but it is very far form finished. If anyone is interested in helping out, let me know.

---

<div class="post-metadata">

**Author:** ![Phlopsi](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/phlopsi/32/13377_2.png) [@Phlopsi](https://users.rust-lang.org/u/Phlopsi)\
**Post date:** [January 13, 2020, 11:26pm UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/59 "2020-01-13T23:26:39Z")

</div>

> [@tkaitchuck](#):
>
> trait FooExt

You probably want to write `trait FooExt: Foo`, if your trait is a strict extension to `Foo`, which the name suggests, i.e. your auto-impl is done for **all** possible `FooExt`.

---

<div class="post-metadata">

**Author:** ![Pauan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/pauan/32/5976_2.png) [@Pauan](https://users.rust-lang.org/u/Pauan)\
**Post date:** [January 14, 2020, 12:43am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/60 "2020-01-14T00:43:47Z")

</div>

@Phlopsi Their code is correct. The purpose of the `FooExt` trait is to add new default methods to an existing trait (like as if they had been defined in `Foo`).

In other words, nobody should ever `impl` a `FooExt` trait, only a `Foo` trait. That's why the blanket `impl` exists, so that way the methods will be _automatically_ available on _all_ `Foo`.

Some examples of the `FooExt` trait pattern: [FutureExt](https://docs.rs/futures/0.3.1/futures/future/trait.FutureExt.html), [TryFutureExt](https://docs.rs/futures/0.3.1/futures/future/trait.TryFutureExt.html), [StreamExt](https://docs.rs/futures/0.3.1/futures/stream/trait.StreamExt.html), [TryStreamExt](https://docs.rs/futures/0.3.1/futures/stream/trait.TryStreamExt.html), [SignalExt](https://docs.rs/futures-signals/0.3.11/futures_signals/signal/trait.SignalExt.html), and [SignalVecExt](https://docs.rs/futures-signals/0.3.11/futures_signals/signal_vec/trait.SignalVecExt.html).

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/rustyyato/32/49247_2.png) [@RustyYato](https://users.rust-lang.org/u/RustyYato)\
**Post date:** [January 14, 2020, 1:14am UTC](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155/61 "2020-01-14T01:14:27Z")

</div>

From `FutureExt`

```rust
pub trait FutureExt: Future {
...

```

Which is what @Phlopsi is proposing, this way no one can implement `FooExt`, they must get the derived version from the blanket impl

[Previous page](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155.md?page=2)

[Next page](https://users.rust-lang.org/t/suggestion-for-making-rusts-trait-system-more-usable-for-generics/35155.md?page=4)
