In Rust, the main tool for abstraction are traits. In C++, there are two tools for abstractions: abstract classes and templates. To get rid of some of the disadvantages of using templates (e.g. hard to read error messages), C++ introduced concepts which are "named sets of requirements".
Both features seem to be fairly similar:
But from what I understand, there are also notable differences. For example, C++'s concepts seem to define a set of expressions that have to be valid instead of listing function signatures. But there is a lot of different and confusing information out there (maybe because concepts only land in C++20?). That's why I'd like to know: what exactly are the differences between and the similarities of C++'s concepts and Rust's traits?
Are there features that are only offered by either concepts or traits? E.g. what about Rust's associated types and consts? Or bounding a type by multiple traits/concepts?
Traits in C++ is like std::numeric_limits or std::iterator_traits . It takes a type and returns some information about that type. The default implementation handles a certain number of cases, and you can specialize it to handle other cases.
A trait in Rust is a group of methods that are defined for a particular type. Traits are an abstract definition of shared behavior amongst different types. So, in a way, traits are to Rust what interfaces are to Java or abstract classes are to C++. A trait method is able to access other methods within that trait.
While C is good for writing minimal code on byte-by-byte pointer-by-pointer level, Rust has powerful features for efficiently combining multiple functions or even whole libraries together.
Ease of use. Most people who use both Rust and C++ say that Rust is easier to use due to its well-defined semantics and its ability to prevent unwanted/undefined behavior. Similarly, C++ has so many features that it can be challenging to keep track.
Disclaimer: I have not yet used concepts, all I know about them was gleaned from the various proposals and cppreference, so take this answer with a grain of salt.
Rust Traits are used both for Compile-Time Polymorphism and, sometimes, Run-Time Polymorphism; Concepts are only about Compile-Time Polymorphism.
The greatest difference between Concepts and Traits is that Concepts use structural typing whereas Traits use nominal typing:
impl Trait for Type
is used to explicitly indicates that a type implements a Trait.There are a number of consequences; in general Nominal Typing is better from a maintainability point of view -- adding a requirement to a Trait -- whereas Structural Typing is better a bridging 3rd party libraries -- a type from library A can satisfy a Concept from library B without them being aware of each other.
Traits are mandatory:
Concepts are entirely optional:
Note: a Constraint is introduced by a requires
clause and specifies either ad-hoc requirements or requirements based on Concepts.
The set of expressible requirements is different:
Rust has no concept of ad-hoc overloading, overloading only occurs by Traits and specialization is not possible yet.
C++ Constraints can be used to "order" overloads from least specific to most specific, so the compiler can automatically select the most specific overload for which requirements are satisfied.
Note: prior to this, either SFINAE or tag-dispatching would be used in C++ to achieve the selection; calisthenics were required to work with open-ended overload sets.
How to use this feature is not quite clear to me yet.
The requirement mechanisms in Rust are purely additive (conjunctions, aka &&
), in contrast, in C++ requires
clauses can contain disjunctions (aka ||
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With