Trait (computer programming): Difference between revisions

Content deleted Content added
Edcrypt (talk | contribs)
Pharo already mentioned - Undid revision 975701652 by Edcrypt (talk)
Xybreus (talk | contribs)
Add archive to dead citation, fix citation warnings (use proper name instead of screen name of author, change non-journal PDF from "cite journal" to "cite report"))
 
(38 intermediate revisions by 22 users not shown)
Line 1:
{{Short description|Set of methods that extend the functionality of a class}}
{{Technical|date=March 2012}}
{{more citations needed|date=November 2022}}
 
In [[computer programming]], a '''trait''' is a concept used in [[object-orientedprogramming programminglanguage|language]], whichconcept that represents a set of [[Method (computer programming)|methods]] that can be used to extend the functionality of a [[Class (computer science)|class]].<ref name="schaerli-ecoop-2003">{{cite journalbook | first1=Nathanael | last1=Schärli | first2=Stéphane | last2=Ducasse | first3=Oscar | last3=Nierstrasz | author-link3=Oscar Nierstrasz | first4=Andrew P. | last4=Black | chapter-url=http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf | titlechapter=Traits: Composable Units of Behaviour | journaltitle=Proceedings of the European Conference on Object-Oriented Programming (ECOOP). | series=Lecture Notes in Computer Science | volume=2743 | year=2003 | pages=248–274 |publisher=Springer |doi=10.1007/978-3-540-45070-2_12 |isbn=978-3-540-45070-2 |citeseerx=10.1.1.1011.8}}</ref><ref>{{cite journal | first1=Stéphane | last1=Ducasse | first2=Oscar | last2=Nierstrasz | first3=Nathanael | last3=Schärli | first4=Roel | last4=Wuyts | first5=Andrew P. | last5=Black | title=Traits: A mechanism for fine-grained reuse. | journal= ACM Transactions on Programming Languages and Systems | volume=28 | issue=2 | pages=331–388 | date=March 2006 | doi=10.1145/1119479.1119483 |citeseerx=10.1.1.64.2480| s2cid=16434119 }}</ref>
 
==CharacteristicsRationale==
In object-oriented programming, behavior is sometimes shared between classes which are not related to each other. For example, many unrelated classes may have methods to [[Serialization|serialize]] objects to [[JSON]]. Historically, there have been several approaches to solve this without duplicating the code in every class needing the behavior. Other approaches include [[multiple inheritance]] and [[mixin|mixins]], but these have drawbacks: the behavior of the code may unexpectedly change if the order in which the mixins are applied is altered, or if new methods are added to the parent classes or mixins.
Traits both provide a set of methods that implement behaviour to a class, and require that the class implement a set of methods that [[Parameter (computer programming)|parameterize]] the provided behaviour.
 
Traits solve these problems by allowing classes to use the trait and get the desired behavior. If a class uses more than one trait, the order in which the traits are used does not matter. The methods provided by the traits have direct access to the data of the class.
For inter-object communication, traits are somewhere between an object-oriented [[Protocol (object-oriented programming)|protocol (interface)]] and a [[mixin]]. An interface may define one or more behaviors via [[Function prototype|method signatures]], while a trait defines behaviors via full method definitions: i.e., it includes the [[Class implementation file|body of the methods]]. In contrast, mixins include full method definitions and may also carry [[State (computer science)|state]] through member variable, while traits usually don't.
 
==Characteristics==
Traits combine aspects of [[Protocol (object-oriented programming)|protocols (interfaces)]] and [[mixins]]. Like an interface, a trait defines one or more [[Function prototype|method signatures]], of which implementing classes must provide implementations. Like a mixin, a trait provides additional behavior for the implementing class.
 
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]], whenbetween moremethods than one trait to be usedprovided by a class has a method with the samedifferent nametraits, the programmer must explicitly disambiguate which one of those methods will be used in the class; thus manually solving the ''[[Multiple inheritance#The diamond problem|diamond problem]]'' of [[multiple inheritance]]. This is different from other composition methods in object-oriented programming, where conflicting names are automatically resolved by [[Scope (computer science)|scoping rules]].
 
Operations which can be performed with traits include:<ref>{{cite report
Whereas mixins can be composed only using the [[Inheritance (object-oriented programming)|inheritance]] operation, traits offer a much wider selection of operations, including:<ref>{{cite journal
|first1 = Kathleen |last1 = Fisher | author1-link = Kathleen Fisher
|first2 = John |last2 = Reppy
Line 31 ⟶ 36:
}}</ref>
* ''symmetric sum'': an operation that merges two disjoint traits to create a new trait
* ''override'' (or ''asymmetric sum''): an operation that forms a new trait by adding methods to an existing trait, possibly [[method overriding|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. (Combining this with the alias operation yields a ''shallow rename'' operation).
 
If a method is excluded from a trait, that method must be provided by the class that consumes the trait, or by a parent class of that class. This is because the methods provided by the trait might call the excluded method.
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''.<!-- This is not always true. See for instance Scala (Chap 12 "Traits" page 226 in "Programming in Scala" isbn 9780981531601 : "The order of mixins is significant" ) -->
Trait composition is [[commutative]] (i.e. given traits ''A'' and ''B'', ''A'' + ''B'' is equivalent to ''B'' + ''A'') and [[associative]] (i.e. given traits ''A'', ''B'', and ''C'', (''A'' + ''B'') + ''C'' is equivalent to ''A'' + (''B'' + ''C'')).<ref name="schaerli-ecoop-2003"/>
* 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''.<ref name="schaerli-ecoop-2003"/>
==Limitations==
While traits offer significant advantages over many alternatives, they do have their own limitations.
 
=== Required methods ===
If a trait requires the consuming class to provide certain methods, the trait cannot know if those methods are [[Semantic_equivalence|semantically equivalent]] to the trait's needs. For some dynamic languages, such as Perl, the required method can only be identified by a method name, not a full [[Type signature|method signature]], making it harder to guarantee that the required method is appropriate.
 
=== Excluding methods ===
If a method is excluded from a trait, that method becomes a 'required' method for the trait because the trait's other methods might call it.
 
==Supported languages==
Traits come originally from the programming language [[Self (programming language)|Self]]<ref>{{cite conference | first1=Gael | last1=Curry | first2=Larry | last2=Baer | first3=Daniel | last3=Lipkie | first4=Bruce | last4=Lee | title=Traits: An approach to multiple-inheritance subclassing | conference=SIGOA Conference on Office Information Systems | pages=1–9 | ___location=Philadelphia, Pennsylvania, USA | year=1982 | publisher=ACM Press | doi=10.1145/966873.806468 }}</ref> and are supported by the following programming languages:
 
* [[AmbientTalk]]: Combines the properties of Self traits (object-based multiple inheritance) and [[Smalltalk]]'s [[Squeak]] traits (requiring explicit composition of traits by the programmer). It builds on the research on ''stateful'' and ''freezable'' traits to enable state within traits, which was not allowed in the first definitions.<ref>{{cite conference | url=http://soft.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf | title=Adding State and Visibility Control to Traits Using Lexical Nesting | conference=European Conference on Object-Oriented Programming (ECOOP 2009) | first1=Tom | last1=Van Cutsem | first2=Alexandre | last2=Bergel | first3=Stéphane | last3=Ducasse | first4=Wolfgang | last4=De Meuter | pages=220–243 | publisher=Springer-Verlag | isbn=978-3-642-03012-3 | date=2009 | series=Lecture Notes in Computer Science | volume=5653 |doi=10.1007/978-3-642-03013-0_11 |citeseerx=10.1.1.372.1265}}</ref>
*[[C Sharp (programming language)|C#]]: Since version 8.0, C# has support for ''default interface methods'',<ref>{{cite web | url=https://docs.microsoft.com/en-gb/dotnet/csharp/whats-new/csharp-8#default-interface-methods | title=Default interface methods | website=What's new in C# 8.0 | publisher=Microsoft | access-date=November 29, 2019}}</ref> which have some properties of traits.<ref>{{cite web | url=https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/ | title=Interfaces in C# 8.0 gets a makeover | website=Default Implementation in Interfaces in C# 8.0 | date=9 September 2019 | publisher=Talking Dotnet | access-date=November 29, 2019}}</ref>
* [[C++]]: Used in [[Standard Template Library]] and the [[C++ standardStandard libraryLibrary]] to support generic [[Container (abstract data structuretype)|container classes]]<ref>{{cite web | url=http://www.sgi.com/tech/stl/iterator_traits.html | title=iterator_traits&lt;Iterator&gt; | website=Standard Template Library | publisher=SGI}}</ref><ref>{{cite magazine | url=http://www.cantrip.org/traits.html | title=Traits: a new and useful template technique | first=Nathan C. | last=Myers | magazine=C++ Report | date=June 1995 | access-date=January 23, 2016}}</ref> and in the [[Boost C++ Libraries|Boost]] TypeTraits library.<ref>{{cite web | url=http://www.boost.org/more/generic_programming.html#traits | title=Generic Programming Techniques: Traits | website=Boost C++ Libraries | first=David | last=Abrahams | access-date=January 23, 2016}}</ref>
* [[Curl (programming language)|Curl]]: Abstract classes as mixins permit method implementations and thus constitute traits by another name.{{citation needed|date=January 2016}}
* [[D (programming language)|D]]: Since version 2.003, the __traits language extension<ref>{{cite web | url=http://dlang.org/traits.html | title=Traits | website=The D Language Reference | publisher=Digital Mars | access-date=January 23, 2016}}</ref> and std.traits module<ref>{{cite web | url=http://dlang.org/phobos/std_traits.html | title=std.traits | website=The D Language — Library Reference | publisher=Digital Mars | access-date=January 23, 2016}}</ref> helper templates provide compile-time traits. Together with other language features (notably templates and mixins), 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.<ref>{{cite web | url=http://dlang.org/class.html#AliasThis | title=Classes | website=The D Language Reference | publisher=Digital Mars | access-date=January 23, 2016}}</ref>
* [[Fortress (programming language)|Fortress]]<ref>{{cite web | url=http://stephane.ducasse.free.fr/Teaching/CoursAnnecy/0506-Master/ForPresentations/Fortress-PLDITutorialSlides9Jun2006.pdf | title=Fortress Programming Language Tutorial | first1=Guy | last1=Steele | first2=Jan-Willem | last2=Maessen | publisher=Sun Microsystems | date=June 11, 2006 | access-date=January 23, 2016}}</ref>
* [[Groovy (programming language)|Groovy]]: Since version 2.3<ref>{{cite web | url=http://www.groovy-lang.org/objectorientation.html#_traits | title=Object Orientation: Traits | website=The Groovy Programming Language | access-date=January 23, 2016}}</ref>
* [[Haskell (programming language)|Haskell]]: In Haskell, Traits are known as [[Type class|Type classes]]es.
* [[Haxe]]: Since version 2.4.0.<ref>{{Cite news|url=https://haxe.org/download/version/2.4.0/|title=Haxe 2.4.0 - Haxe - The Cross-platform Toolkit|work=Haxe - The Cross-platform Toolkit|access-date=2017-09-12}}</ref> Called ''Static Extension''<ref>{{Cite news|url=https://haxe.org/manual/lf-static-extension.html|title=Manual - Haxe - The Cross-platform Toolkit|work=Haxe - The Cross-platform Toolkit|access-date=2017-09-12}}</ref> in the manual, it uses <code>using</code> keyword
* [[Java (programming language)|Java]]: Since version 8, Java has support for ''default methods'',<ref>{{cite web | url=https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html | title=Default Methods | website=The Java Tutorials | publisher=Oracle | access-date=January 23, 2016}}</ref> which have some properties of traits.<ref>{{cite journal | url=https://hal.inria.fr/inria-00432538/ | title= FeatherTrait: A Modest Extension of Featherweight Java | first1=Luigi | last1=Liquori | first2=Arnaud | last2=Spiwack | journal= ACM Transactions on Programming Languages and Systems | date=2008 | volume= 30 | issue= 2 | pages= 11:1 |doi=10.1145/1330017.1330022| s2cid= 17231803 | doi-access=free }}</ref><ref>{{cite journal | url=https://hal.inria.fr/inria-00432540/ | title= Extending FeatherTrait Java with Interfaces | first1=Luigi | last1=Liquori | first2=Arnaud | last2=Spiwack | journal= Theoretical Computer Science | date=2008 | volume= 398 | issue= 1–3 | pages= 243–260 |doi=10.1016/j.tcs.2008.01.051| s2cid= 12923128 | doi-access=free }}</ref><ref>{{cite conference | url=https://hal.inria.fr/hal-01026531/en | title=Trait-oriented Programming in Java 8 | first1=Viviana | last1=Bono | first2=Enrico | last2=Mensa | first3=Marco | last3=Naddeo | conference=International Conference on Principles and Practices of Programming on the Java Platform: virtual machines, languages, and tools (PPPJ ’14) | date=September 2014 | ___location=Kraków, Poland | conference-url=http://pppj2014.pk.edu.pl/ |pages=181–6 |doi=10.1145/2647508.2647520 |citeseerx=10.1.1.902.161}}</ref><ref>{{cite web | title=Definition of the Trait Pattern in Java | url=http://ageofjava.com/2016/02/definition-of-trait-pattern-in-java.html | archive-url=https://web.archive.org/web/20160804005218/http://ageofjava.com/2016/02/definition-of-trait-pattern-in-java.html | url-status=dead | archive-date=August 4, 2016 | website=Age of Java | date=February 3, 2016 | access-date=February 3, 2016 | first=Emil | last=Forslund}}</ref>
* [[JavaScript]]: Traits can be implemented via functions and delegations<ref>{{cite web | url=http://peterseliger.blogspot.com/2014/04/the-many-talents-of-javascript.html | title=The Many Talents of JavaScript | first=Peter | last=Seliger | date=April 11, 2014 | access-date=January 23, 2015}}</ref> or through libraries that provide traits.<ref>{{cite web | url=https://traitsjs.github.io/traits.js-website/ | title=Traits.js: Traits for JavaScript | access-date=January 23, 2016}}</ref><ref>{{cite journal | url=http://soft.vub.ac.be/Publications/2012/vub-soft-tr-12-19.pdf | title=Robust Trait Composition for Javascript | first1=Tom | last1=Van Cutsem | first2=Mark S. | last2=Miller | journal=Science of Computer Programming| year=2012 | access-date=January 23, 2016}}</ref><ref>{{cite web | url=https://cocktailjs.github.io/ | title=CocktailJS | access-date=January 23, 2016}}</ref>
* [[Julia (programming language)|Julia]]: Several packages implement traits, e.g.,<ref>{{cite web | url=https://github.com/mauro3/SimpleTraits.jl | title=SimpleTraits.jl | author=mauro3Mauro Werder | website=[[GitHub]] | access-date=March 23, 2017}}</ref>
* [[Kotlin (programming language)|Kotlin]]: Traits have been called ''interfaces''<ref>{{cite web | url=http://kotlinlang.org/docs/reference/interfaces.html | title=Interfaces | website=Kotlin Reference | publisher=JetBrains | access-date=January 23, 2016}}</ref> since M12.<ref>{{cite web | url=http://blog.jetbrains.com/kotlin/2015/05/kotlin-m12-is-out/ | title=Kotlin M12 is out! | first=Andrey | last=Breslav | website=Kotlin Blog | publisher=JetBrains | date=May 29, 2015 | access-date=January 23, 2016}}</ref>
* [[Lasso (programming language)|Lasso]]<ref>{{cite web | url=http://lassoguide.com/language/traits.html | title=Traits | website=Lasso Language Guide | publisher=LassoSoft | date=January 6, 2014 | access-date=January 23, 2016}}</ref>
* [[Mojo (programming language)|Mojo]]: Since version 0.6.0<ref>{{Cite web |title=Modular Docs - Mojo🔥 changelog |url=https://docs.modular.com/mojo/changelog.html#v0.6.0-2023-12-04 |access-date=2023-12-13 |website=docs.modular.com |language=en}}</ref>
* [[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 (Perl)|Moose]], Role::Tiny and Role::Basic. Roles are part of the sister language [[Raku (programming language)|Raku]]. <ref>{{cite web | url=http://www.modernperlbooks.com/mt/2009/04/the-why-of-perl-roles.html | title=The Why of Perl Roles | author=chromatic | date=April 30, 2009 | access-date=January 23, 2016}}</ref> With the acceptance of the ''Corinna OOP Proposal''<ref>{{cite web | url=https://github.com/Ovid/Cor/blob/master/rfc/mvp.md | title=Corinna OOP Proposal | website=Corinna RFC | author=Curtis "Ovid" Poe | access-date=September 30, 2022}}</ref> Perl will have roles native to the language as part of a modern OOP system.
* [[PHP]]: Since version 5.4,<ref>{{cite web | url=http://www.php.net/manual/en/language.oop5.traits.php | title=Traits | website=PHP Documentation | publisher=The PHP Group | access-date=January 23, 2016}}</ref><ref name="php:rfc:horizontalreuse">{{cite web | last=Marr | first=Stefan | title=Request for Comments: Horizontal Reuse for PHP | url=https://wiki.php.net/rfc/horizontalreuse | website=PHP.net wiki | publisher=The PHP Group | date=January 9, 2011 | access-date=January 31, 2011}}</ref> PHP allows users to specify templates that provide the ability to "inherit" from more than one (trait-)class, as a pseudo [[multiple inheritance]].
* [[Python (programming language)|Python]]: Via a third-party library,<ref>{{cite web | url=http://py3traits.readthedocs.org/ | title=py3traits Documentation | first=Teppo | last=Perä | access-date=January 23, 2016}}</ref><ref>{{cite web | url=https://github.com/Debith/py2traits | title=py2traits | first=Teppo | last=Perä | website=[[GitHub]] | access-date=January 23, 2016| date=2015-03-25 }}</ref> or via higher-order mixin classes<ref>{{cite web | url=http://stupid-python-tricks.blogspot.com/2015/04/computed-properties-and-higher-order.html | title = Higher Order Mixin Classes | archive-date = 2016-10-09 | archive-url = https://web.archive.org/web/20161009062141/http://stupid-python-tricks.blogspot.com/2015/04/computed-properties-and-higher-order.html }}</ref>
* [[Racket (programming language)|Racket]]: Supports traits as a library and uses macros, structures, and first-class classes to implement them.<ref>{{cite web | url=http://docs.racket-lang.org/reference/trait.html | title=Traits | website=The Racket Reference | access-date=January 23, 2016}}</ref>
* [[Ruby (programming language)|Ruby]]: ''Module mixins'' can be used to implement traits.<ref>{{cite web | url=http://ruby-naseby.blogspot.com/2008/11/traits-in-ruby.html | title=Traits in Ruby | website=Ruby Naseby | author=David Naseby | date=February 14, 2004 | access-date=January 23, 2016}}</ref>
Line 66 ⟶ 79:
* [[Scala (programming language)|Scala]]<ref>{{cite web | url=http://www.scala-lang.org/node/126 | title=Traits | website=A Tour of Scala | publisher=[[École polytechnique fédérale de Lausanne]] | access-date=January 23, 2016}}</ref><ref>{{cite web | url=http://www.ibm.com/developerworks/java/library/j-scala04298/ | title=The busy Java developer's guide to Scala: Of traits and behaviors | first=Ted | last=Neward | website=IBM developerWorks | publisher=IBM | date=April 29, 2008 | access-date=January 23, 2016}}</ref> trait is builtin supported with the key word <code>trait</code>.
* [[Smalltalk]]: Traits are implemented in two dialects of Smalltalk, [[Squeak]]<ref name="schaerli-ecoop-2003"/> and [[Pharo]].<ref>{{cite web | url=http://pharo.gemtalksystems.com/book/LanguageAndLibraries/Traits/ | title=Traits in 10 minutes | website=Pharo: The CollaborActive Book | access-date=January 23, 2016}}</ref>
* [[Swift (programming language)|Swift]]: Traits can be implemented with ''protocol extensions''.<ref>{{cite web | url=httphttps://matthijshollemansmachinethink.comnet/2015/07/22blog/mixins-and-traits-in-swift-2.0/ | title=Mixins and Traits in Swift 2.0 | first=Matthijs | last=Hollemans | date=July 22, 2015 | access-date=January 23, 2016}}</ref>
 
== Examples ==
Line 74 ⟶ 87:
using System;
 
namespace CSharp8NewFeatures;
 
interface ILogger
{
// Traditional interface ILoggermethods
void LogWarningLog(string message);
void LogError(Exception exception);
 
// Default interface method
void LogWarning(string message)
{
Console.WriteLine(message);
// Traditional interface methods
} void Log(string message);
}
void LogError(Exception exception);
 
class Logger : ILogger
// Default interface method
{
void LogWarning(string message)
public void Log(string message)
{
{
Console.WriteLine(message);
}
}
 
public void LogError(Exception exception)
class Logger : ILogger
{
public void LogConsole.WriteLine(string messageexception.ToString());
{
Console.WriteLine(message);
}
 
public void LogError(Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
}
 
class Program
{
static void Main(string[] args)
{
staticILogger voidlogger Main(string[]= argsnew Logger();
{
ILogger logger = new Logger();
 
logger.LogWarning("Some warning message");
}
}
}
Line 181 ⟶ 193:
 
=== Rust ===
A trait in Rust declares a set of methods that a type must implement.<ref>{{Cite web | archive-url=https://web.archive.org/web/20230529022632/http://gradebot.org/doc/ipur/trait.html|archive-date=2023-05-29|url-status=dead|url=http://gradebot.org/doc/ipur/trait.html | title=Traits - Introduction to Programming Using Rust}}</ref> Rust compilers require traits to be explicated, which ensures the safety of [[Generic programming|generics]] in Rust.
 
<syntaxhighlight lang="rust">
// type T must have the "Ord" trait
// so that ">" and "<" operations can be done
fn get_maxmax<T: Ord>(a: &[T]) -> Option<&T> {
let mut result = a.getfirst(0)?;
for n in a {
if *n > *result {
result = &n;
{}
}
{}
}
Some(result)
}
</syntaxhighlight>
 
To simplify tedious and repeated implementation of traits like <code>Debug</code> and <code>Ord</code>, the <code>derive</code> macro can be used to request compilers to generate certain implementations automatically.<ref>{{Cite web | url=https://doc.rust-lang.org/book/first-edition/traits.html | title=Traits - the Rust Programming Language}}</ref> Derivable traits include: <code>Clone</code>, <code>Copy</code>, <code>Debug</code>, <code>Default</code>, <code>PartialEq</code>, <code>Eq</code>, <code>PartialOrd</code>, <code>Ord</code> and <code>Hash</code>.
 
==See also==
* [[extensionExtension method]]
 
* [[interfaceInterface (object-oriented programming)]]
* [[extension method]]
* [[Parametric polymorphism]]
* [[interface (object-oriented programming)]]
* [[UFCS]]
 
Line 214 ⟶ 226:
[[Category:Programming language topics]]
[[Category:Type theory]]
[[Category:Articles with example C Sharp code]]
[[Category:Articles with example PHP code]]
[[Category:Articles with example Rust code]]