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) {}