Traits
Traits are designed as a mechanism for extending existing types with functionality.
Both explicit and implicit traits exist; explicit traits (trait Foo
) must be explicitly implemented for a given type. They implement nominal subtyping. Implicit traits (implicit trait Foo
) apply to all types that match the “pattern” (structure) described within, thus implementing structural subtyping.
Note: The example specifies what seems like operator overloading. While the D approach seems fine, I don’t fully know yet how it will work. opAdd
, __add__
, and similar have the issue that the relationship between operators and names can be unclear. On the other hand, operator+
(keyword-based) create for messy syntax, are by themselves ambiguous (consider the C++ operator++(int)
hack), and either cover too much (all of < <= > >=
must be manually implemented, as opposed to a single opCmp
), or leave the user guessing as to which operators are available for overloading in this manner and which aren’t.
struct SomeStruct
{
string foo;
int bar;
// implemented as an anonymous trait; see below for equivalent [A]
int getSomething() { return bar + 10; }
}
trait Addable
{
// this_t is alias for the implementing type
// TODO: unsure of `this_t` keyword name (I dislike the idea of a _t suffix *in a keyword*, though it does make sense)
this_t opAdd(this_t b);
}
// TODO: Should we even *have* implicit traits? They can be very useful, though.
implicit trait Divisible
{
this_t opDiv(this_t b);
}
// implement a trait for SomeStruct
extend SomeStruct: Addable
{
// `this_t` when *extending* is just a direct alias for `SomeStruct`
// it is allowed here to avoid repetition of `SomeStruct`, and for symmetry with the trait
this_t opAdd(this_t b) { ... }
}
// [A] equivalent to SomeStruct.getSomething above
extend SomeStruct // implemented as an anonymous trait that only SomeStruct implements
{
int getSomething() { return bar + 10; }
}