This article may be too technical for most readers to understand.(March 2012) |
In computer programming, a trait is a concept used in object-oriented programming, which represents a set of methods that can be used to extend the functionality of a class.[1][2]
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 (interface) 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:[3][4]
Traits are composed in the following ways:
Traits come originally from the programming language Self[5] and are supported by the following programming languages:
using
keywordtrait
.On C# 8.0, it is possible to define an implementation as a member of an interface.
using System;
namespace CSharp8NewFeatures
{
interface ILogger
{
// Traditional interface methods
void Log(string message);
void LogError(Exception exception);
// Default interface method
void LogWarning(string message)
{
Console.WriteLine(message);
}
}
class Logger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
public void LogError(Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
class Program
{
static void Main(string[] args)
{
ILogger logger = new Logger();
logger.LogWarning("Some warning message");
}
}
}
This example uses a trait to enhance other classes:
// The template
trait TSingleton
{
private static $_instance = null;
private function __construct() {} // Must have private default constructor and be aware not to open it in the class
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
class FrontController
{
use TSingleton;
}
// Can also be used in already extended classes
class WebSite extends SomeClass
{
use TSingleton;
}
This allows simulating aspects of multiple inheritance:
trait TBounding
{
public $x, $y, $width, $height;
}
trait TMoveable
{
public function moveTo($x, $y)
{
// …
}
}
trait TResizeable
{
public function resize($newWidth, $newHeight)
{
// …
}
}
class Rectangle
{
use TBounding, TMoveable, TResizeable;
public function fillColor($color)
{
// …
}
}
A trait in Rust declares a set of methods that a type must implement.[43] 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<T: Ord>(a: &[T]) -> Option<&T> {
let mut result = a.get(0)?;
for n in a {
if *n > *result {
result = &n;
}
}
Some(result)
}
To simplify tedious and repeated implementation of traits like Debug
and Ord
, the derive
macro can be used to request compilers to generate certain implementations automatically.[44] Derivable traits include: Clone
, Copy
, Debug
, Default
, PartialEq
, Eq
, PartialOrd
, Ord
and Hash
.
|journal=
(help)
By: Wikipedia.org
Edited: 2021-06-18 14:09:04
Source: Wikipedia.org