Traits
Traits are how Ki adds functionality to types without changing the type itself.
trait HasBirthdate {
@fields {
Date birthdate
}
@methods {
get age (DateDelta) {
return Date.today() - self.birthdate
}
}
}
trait HasName {
@fields {
string name
}
}
trait Human (HasName, HasBirthdate) {
@fields {
uint height
uint weight
}
}
While there is some overlap between traits and mixins in computer science, most agree they are more specific than interfaces. An interface only specifies fields and methods, not behavior. A trait can (optionally) provide all three.
In Ki, traits can include other traits. In the above example, Human
includes
both HasName
and HasBirthdate
.
- Basic traits (add/sub/mul/div/iter/eq/index/read/writ/seek -able)
- Look at Rust for this
Traits are very helpful for defining generic functions. For example, this is
a num
-specific add function:
fn add(num x, num y) (num) {
return x + y
}
But (conceivably), other things can be added together. This is a generic add function:
trait Addable {
fn add(Addable other) (Addable)
}
type StringBuffer (Addable) {
@fields {
heapvar buf: dynarray<rune>
}
get value (string) {
:initializers {
fn(string value) {
alloc: value.length
self.buf: dynarray {
type: <rune>
alloc: alloc
}
self.buf.extend(value)
}
fn(uint alloc) {
self.buf: dynarray {
type: <rune>
alloc: alloc
}
}
}
fn :add(StringBuffer other) (StringBuffer) {
heapvar sb: StringBuffer(alloc: self.buf.alloc + other.buf.alloc)
sb.buf.extend(self.buf)
sb.buf.extend(other.buf)
return sb
}
fn add(Addable x, Addable y) (Addable) {
return x.add(y)
}
Now, anything that implements Addable
can be added.
This can also be implemented using operator overloading; in fact, that is the idiomatic way of doing it.