Types

New types are declared with the data keyword and they come in two flavours

Records

You can declare records like so:

type Person(firstName: String, lastName: String, age: Int)

you can then create a value of that type

let p = Person("John", "Doe", 26)

and access its fields

p.firstName # "John"

if a variable is declared as (im)mutable then all its fields are also (im)mutable

let p1 = Person("John", "Doe", 26)
p.firstName = "Jane" # error

let p2 = Person("John", "Doe", 26)
p2.firstName = "Jane" # ok
p2.firstName # "Jane"

The first declaration introduces

  • A type named “Person”
  • A constructor called “Person” of type (String, String, Int) -> Person
  • Accessors named .firstname, .lastname, and .age, of types Person -> String, Person -> String and Person -> Int respectively

Enumerations

You can declare records like so:

type Result {
    Failure(),
    Success(value: Int)
}

you can then create a value of that type

let s: Result = Success(5);
let f: Result = Failure();

Unlike records, enumerations do not create accessors. It wouldn’t be possible, since fields could be missing! In this example, s has a value, but f does not, so what would a hypothetical .value accessor return?

Since you can’t access the contents of an enumeration directly, the only way is to use Pattern Matching

The first declaration introduces

  • A type named “Person”
  • Constructors named Failure and Success, with types () -> Result and Int -> Result, respectively
  • No Accessors

Polymorphic types (generics)

Types in Kima can be defined in terms of a number of type parameters. For example, the Result type from before can be modified to be able to carry any result value, not just integers:

type Numbered<t>(num: Int, val: t)

You can then instantiate that type when declaring a variable:

let x: Numbered<String> = Numbered(1, "hi");

Or it can be used in a function:

fun printIndex(val: Numbered<t>) -> Unit {
    print(val.num);
}

In the above declaration, the function itself actually takes t as a type parameter. Kima can infer the type parameters however and so there is no need to specify them. If you still want to however, you can do that:

fun printIndex<t>(val: Numbered<t>) -> Unit {
    print(val.num);
}