Traits both provide a set of methods that implement behaviour to a class, and require that the class implement a set of methods that parameterize the provided behaviour. For inter-object communication, traits are somewhere between an object-oriented protocol and a mixin. An interface may define one or more behaviors via method signatures, while a trait defines behaviors via full method definitions: i.e., it includes the body of the methods. In contrast, mixins include full method definitions and may also carry state through member variable, while traits usually don't. Hence an object defined as a trait is created as the composition of methods, which can be used by other classes without requiring multiple inheritance. In case of a naming collision, when more than one trait to be used by a class has a method with the same name, the programmer must explicitly disambiguate which one of those methods will be used in the class; thus manually solving the diamond problem of multiple inheritance. This is different from other composition methods in object-oriented programming, where conflicting names are automatically resolved by scoping rules. Whereas mixins can be composed only using the inheritance operation, traits offer a much wider selection of operations, including:
symmetric sum: an operation that merges two disjoint traits to create a new trait
override : an operation that forms a new trait by adding methods to an existing trait, possibly overriding some of its methods
alias: an operation that creates a new trait by adding a new name for an existing method
exclusion: an operation that forms a new trait by removing a method from an existing trait..
Traits are composed in the following ways:
Trait composition is commutative; the ordering of adding traits does not matter. For example, given trait S = A + B, then trait T = B + A is the same as S.
Conflicting methods are excluded from the composition.
Nested traits are equivalent to flattened traits; the composition hierarchy does not affect the traits behaviour. For example, given trait S = A + X, where X = B + C, then trait T = A + B + C is the same as S.
Supported languages
Traits come originally from the programming languageSelf and are supported by the following programming languages:
AmbientTalk: Combines the properties of Self traits and Smalltalk's Squeak traits. It builds on the research on stateful and freezable traits to enable state within traits, which was not allowed in the first definitions.
C#: Since version 8.0, C# has support for default interface methods, which have some properties of traits.
Curl: Abstract classes as mixins permit method implementations and thus constitute traits by another name.
D: Since version 2.003, the __traits language extension and std.traits module helper templates provide compile-time traits. Together with other language features, they allow flexible automatic generation of methods based on interfaces and types. D also allows explicit aliasing of member methods and variables, including forwarding to multiple member classes.
OCaml: Traits can be implemented using a variety of language features: module and module type inclusion, functors and functor types, class and class type inheritance, et cetera.
Perl: Called roles, they are implemented in Perl libraries such as Moose, Role::Tiny and Role::Basic. Roles are part of the sister languageRaku.
PHP: Since version 5.4, PHP allows users to specify templates that provide the ability to "inherit" from more than one class, as a pseudo multiple inheritance.
Python: Via a third-party library, or via higher-order mixin classes
Racket: Supports traits as a library and uses macros, structures, and first-class classes to implement them.
Ruby: Module mixins can be used to implement traits.
Scala trait is builtin supported with the key wordtrait.
Smalltalk: Traits are implemented in two dialects of Smalltalk, Squeak and Pharo.
Swift: Traits can be implemented with protocol extensions.
Examples
C#
On C# 8.0, it is possible to define an implementation as a member of an interface. using System; namespace CSharp8NewFeatures
PHP
This example uses a trait to enhance other classes: // The template trait TSingleton class FrontController // Can also be used in already extended classes class WebSite extends SomeClass
This allows simulating aspects of multiple inheritance: trait TBounding trait TMoveable trait TResizeable class Rectangle
Rust
A trait in Rust declares a set of methods that a type must implement. Rust compilers require traits to be explicated, which ensures the safety of generics in Rust. // type T must have the "Ord" trait // so that ">" and "<" operations can be done fn get_max -> Option<&T>
To simplify tedious and repeated implementation of traits like Debug and Ord, derive can be used to request compilers to generate certain implementations automatically. Derivable traits include: Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord and Hash.