Components
Components serve two purposes in Ki. First, programmers can add them to types, and second, they can use them in functions to indicate that the function requires an argument to have certain components.
Using Components
The canonical example is an "area" interface/trait/mixin:
component AreaCalculator {
get area: num {
return self.width * self.height
}
}
struct RectangleStruct {
val width: uint
val height: uint
}
type Rectangle (RectangleStruct) {
:components {
AreaCalculator
}
}
Bundling
Components can also be bundled.
struct Position {
var x: int
var y: int
var z: int
}
struct Direction {
var x: int
var y: int
var z: int
}
struct Vector {
var direction: Direction
var magnitude: int
}
struct Actor {
var speed: u8
var health: u8
var strength: u8
var position: Position
var direction: Vector
}
struct Fireball {
var strength: uint
var position: Position
var direction: Vector
}
component FireballShooter {
:dependencies {
var strength: uint
var speed: uint
var position: Position
var direction: Direction
}
fn shoot_fireball(): (Fireball) {
return(Fireball(
strength: self.strength * 2
position: Position(
self.position.x
self.position.y
self.position.z
)
direction: Vector(
self.direction.x
self.direction.y
self.direction.z
self.speed * 2
)
))
}
}
component Threatener {
fn threaten() {
echo("Grrrrr!")
}
}
Writing a function that expects a FireballShooter
is easy:
fn shoot_fireball(shooter: &Fireball) {
echo("shooting a fireball!")
}
But if you want both a FireballShooter
and a Threatener
, you can bundle
those components together into a new component.
component ThreateningFireballShooter {
:components {
FireballShooter
Threatener
}
}
Or, shorthand:
component ThreateningFireballShooter(FireballShooter, Threatener) {}