3 Answers

  1. Patrick- Reply

    2019-11-13

    At the basic level, there's not much difference, but they're still there.

    Haskell describes functions or values defined in a typeclass as 'methods', just as traits describe OOP methods in the objects they enclose. However, Haskell deals with these differently, treating them as individual values rather than pinning them to an object as OOP would lead one to do. This is about the most obvious surface-level difference there is.

    The one thing that Rust could not do, up until recently, was higher-order typed traits, such as the infamous Functor and Monad typeclasses.

    This means that Rust traits could only describe what's often called a 'concrete type', in other words, one without a generic argument. Haskell, however, can make higher-order typeclasses which use types similar to how higher-order functions use other functions, using one to describe another. We couldn't implement the typeclasses aforementioned in Rust, because it didn't support this feature that is regarded as basic, and even essential, in Haskell. Thankfully, this has been implemented recently with associated items.* However, this is not idiomatic Rust, and is generally considered a 'hack'.

    It is also mentionable, as said in the comments, that GHC (Haskell's principal compiler) supports further options for typeclasses, including multi-parameter (i.e. many types involved) typeclasses, and functional dependencies, a lovely option that allows for type-level computations, and leads on to type families. To my knowledge, Rust has neither funDeps or type families, though it may in the future.†

    All in all, whilst traits and typeclasses may seem equivalent on the surface, they do have a lot of differences when compared more deeply, when considering numerous qualities.


    * On a side note, Swift, despite having traits, has no such higher-typing mechanism. A future update to the language, maybe?

    † A nice article on Haskell's typeclasses (including higher-typed ones) can be found here, and an equally good one on Rust's traits is kept here, though is unfortunately a tad out-of-date.

  2. Peter- Reply

    2019-11-13

    I think the current answers overlook the most fundamental differences between Rust traits and Haskell type classes. These differences have to do with the way traits are related to object oriented language constructs. For information about this, see the Rust book.

    1. A trait declaration creates a trait type. This means that you can declare variables of a such a type (or rather, references of the type). You can also use trait types as parameters on function, struct fields and type parameter instantiations.

      A trait reference variable can at runtime contain objects of different types, as long as the runtime type of the referenced object implements the trait.

      // The shape variable might contain a Square or a Circle, 
      // we don't know until runtime
      let shape: &Shape = get_unknown_shape();
      
      // Might contain different kinds of shapes at the same time
      let shapes: Vec<&Shape> = get_shapes();
      

      This is not how type classes work. Type classes create no types, so you can't declare variables with the class name. Type classes act as bounds on type parameters, but the type parameters must be instantiated with a concrete type, not the type class itself.

      You can not have a list of different things of different types which implement the same type class. (Instead, existential types are used in Haskell to express a similar thing.)

    2. Trait methods can be dynamically dispatched. This is strongly related to what is described in the bullet above.

      Dynamic dispatch means that the runtime type of the object a reference points is used to determine which method that is called though the reference.

      let shape: &Shape = get_unknown_shape();
      
      // This calls a method, which might be Square.area or
      // Circle.area depending on the runtime type of shape
      print!("Area: {}", shape.area());
      

      Again, existential types are used for this in Haskell.

    In Conclusion

    It seems to me like traits are essentially the same concept as type classes. It addition, they have the functionality of object oriented interfaces.

    (Haskell's type classes are more advanced, since Haskell has for example higher-kinded types and extension like multi-parameter type classes. But I think they are essentially the same.)

  3. Philip- Reply

    2019-11-13

    Rust's “traits” are analogous to Haskell's type classes.

    The main difference with Haskell is that traits only intervene for expressions with dot notation, i.e. of the form a.foo(b).

    Haskell type classes extend to higher-order types. Rust traits only don't support higher order types because they are missing from the whole language, i.e. it's not a philosophical difference between traits and type classes

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>