Does anyone know of any languages that have something similar to rust's traits?

I am writing a document about programming paradigm and I would like to know more about how traits in rust work. What really is a trait? I saw on a post in stack overflow Answer to this question that a trait can be used as a trait or a type. I would really like someone to explain what a trait is on a fundamental level and what can we do with them. What do they look like when taken to extremes?

1 Like

My understanding is that haskell typeclasses are extremely similar.

Can confirm, Haskell’s “class”es, aka “type classes”, are essentially the same. They don’t call one of the type arguments “Self” since the language has no method syntax, and also there are no strictly enforced orphan rules (which means Haskell is actually not type-safe in this regard), but those are rather minor differences.

2 Likes

A trait is a partial interface specification for a type, which can be shared by multiple types. If all you know about a type T, for example, is that it implements Display, then you can still call T::fmt(...) or pass it to generic functions that can accept any type that implements Display.

Trait objects are a distinct but related concept. The compiler defines a type for simple traits that uses a virtual method table (vtable) to encapsulate the detail of which concrete type was used to create it. For example: the compiler defines the type dyn Display, which implements the trait Display, and can be created from any¹ type that itself implements Display (like u32 and String).

This lets you do things like store lots of different types in a Vec or other collection, as long as they all implement the same trait:

let v: Vec<Box<dyn Display>> = vec![
    Box::new(42),
    Box::new("hello")
];

println!("[{}, {}]", &v[0], &v[1]);

¹ There are a few restrictions and exceptions throughout that I'm leaving out for the sake of clarity.

3 Likes

The question you linked to was talking about trait objects. On that note: Haskell doesn’t have a special notion of “trait objects”. This is because the language is more “dynamic” than Rust in the first place, in that generic functions are not implemented using monomorphization, and trait bounds (aka type class constraints) are always implemented using a form of dictionary-passing (of course, the compiler will be able to optimize many instances of this dictionary-passing, especially after inlining). This means that something akin to trait objects can be implemented in Haskell using a more general concept of “existential types” (different from the same term sometimes used in Rust), and the implementation is rather straightforward in that the existing dictionaries can be stored alongside the data to achieve the type erasure that trait objects achieve.

1 Like

Feel free to also take a look at my replies in this topic which discusses how to make sense of traits with type parameters and/or associated types.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.