> ## Documentation Index
> Fetch the complete documentation index at: https://docs.astrakairo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Kairo Type System: Scalars, Collections, and Domain Types

> Understand Kairo's type system: scalars, collections, nullability, and the value vs. object distinction that shapes business domain modeling.

Kairo's type system is designed around one central idea: types should reflect the business domain, not just the data structure. The distinction between a `value` (compared by its content) and an `object` (compared by its identity) is not just technical — it encodes how a concept behaves in the real world. A `Money` amount with the same number is the same amount regardless of which instance you hold; a `Customer` with the same name is still a different person. Kairo makes this distinction explicit, and all other type-system choices — non-null by default, no implicit conversions, no type aliases — serve the same goal of keeping domain intent clear and unambiguous.

## Scalar Types

Kairo provides six built-in scalar types. There are no automatic widening conversions between them.

| Type      | Description                                                   |
| --------- | ------------------------------------------------------------- |
| `Bool`    | Boolean value: `true` or `false`                              |
| `Text`    | Unicode text string (the primary text type — not `String`)    |
| `Int32`   | 32-bit signed integer                                         |
| `Int64`   | 64-bit signed integer                                         |
| `Decimal` | Arbitrary-precision decimal (default for fractional literals) |
| `Float64` | 64-bit IEEE 754 floating-point (must be typed explicitly)     |

```kairo theme={null}
let label: Text = "Pending"
let count: Int32 = 42
let price: Decimal = 19.99
let ratio: Float64 = 0.75
let active: Bool = true
```

<Note>
  `Decimal` is the default type inferred for fractional literals like `19.99`. If you need `Float64`, you must annotate the binding explicitly. This keeps financial and domain-numeric logic free from floating-point surprises.
</Note>

<Warning>
  Kairo has no broad implicit conversions. You cannot assign an `Int32` where an `Int64` is expected, or a `Decimal` where a `Float64` is expected, without an explicit conversion.
</Warning>

## Temporal Types

Kairo includes first-class temporal types for dates, times, and durations. These are part of the Core prelude and require no import.

| Type       | Description                                          |
| ---------- | ---------------------------------------------------- |
| `Date`     | Calendar date (year, month, day) — no time component |
| `Time`     | Time of day — no date component                      |
| `DateTime` | Combined date and time — no timezone                 |
| `Instant`  | A precise point in time (UTC-based, timezone-aware)  |
| `Duration` | A length of time (e.g., 3 hours, 2 days)             |

```kairo theme={null}
let today: Date = Date.today()
let now: Instant = Instant.now()
let meetingTime: DateTime = DateTime.of(today, Time.of(14, 30))
let delay: Duration = Duration.ofMinutes(15)
```

## Collection Types

Kairo's built-in collections come in immutable and mutable variants. Immutable collections are the default — they cannot be modified after construction.

### Immutable Collections

| Type        | Description                             |
| ----------- | --------------------------------------- |
| `List<T>`   | Ordered sequence of elements            |
| `Set<T>`    | Unordered collection of unique elements |
| `Map<K, V>` | Key-value mapping                       |

### Mutable Collections

| Type              | Description                                 |
| ----------------- | ------------------------------------------- |
| `MutableList<T>`  | Ordered sequence that supports add/remove   |
| `MutableSet<T>`   | Unique-element set that supports add/remove |
| `MutableMap<K,V>` | Key-value map that supports put/remove      |

```kairo theme={null}
let tags: List<Text> = List.of("urgent", "review")
let ids: Set<CustomerId> = Set.of(id1, id2)
let index: Map<Text, Int32> = Map.of("a", 1, "b", 2)

var queue: MutableList<OrderId> = MutableList.empty()
queue.add(orderId)
```

<Tip>
  Prefer immutable collections in `value` types and function return positions. Use `MutableList`, `MutableSet`, and `MutableMap` only inside `object` types where state change is intentional.
</Tip>

## Nullability

All types in Kairo are **non-null by default**. A value can only be `null` if its type is explicitly marked nullable with a trailing `?`.

```kairo theme={null}
let name: Text = "Kairo"        // cannot be null
let nickname: Text? = null      // explicitly nullable
```

You must handle the nullable case before using a nullable value. Kairo will not let you call methods on a `T?` as if it were a `T`.

```kairo theme={null}
let display: Text = match nickname {
    null => name
    else => nickname
}
```

<Warning>
  Avoid nullable types in domain `value` declarations unless the absence of a value is genuinely meaningful in your domain. In most cases, a dedicated `enum` or an optional wrapper `value` communicates intent more clearly.
</Warning>

## `value` Declarations

A `value` is an immutable, content-based domain type. Two `value` instances with identical field contents are considered equal — there is no notion of reference identity. Use `value` for domain concepts that are defined by what they contain: money amounts, identifiers, addresses, measurements.

```kairo theme={null}
public value Money {
    amount: Decimal
    currency: Text
}

public value CustomerId {
    value: Text
}
```

Members of a `value` are always immutable. You cannot mark a member `var` inside a `value`. All stored members must themselves be value-like — you cannot embed an `object`-typed member inside a `value`.

```kairo theme={null}
public value OrderSummary {
    orderId: OrderId
    total: Money
    lineCount: Int32
}
```

## `object` Declarations

An `object` is an identity-bearing, stateful type. Two `object` instances are distinct even if all their fields are identical — identity is intrinsic. Use `object` for domain concepts that change over time and have a lifecycle: customers, orders, sessions, services.

```kairo theme={null}
public object Customer {
    id: CustomerId
    var name: Text

    init(id: CustomerId, name: Text) {
        this.id = id
        this.name = name
    }

    func rename(newName: Text) {
        this.name = newName
    }
}
```

Mark mutable members with `var`. Immutable members (no `var`) can only be set in `init`. Each `object` has exactly one `init` in v0.1.

## `contract` Declarations

A `contract` declares a capability promise — a named set of requirements that any conforming type must satisfy. Contracts play the role that interfaces play in other languages.

```kairo theme={null}
public contract Named {
    name: Text { get }
}

public contract Renameable {
    func rename(newName: Text)
}
```

Declare that a type conforms to one or more contracts by listing them after a colon in the type declaration:

```kairo theme={null}
public object Customer : Named, Renameable {
    id: CustomerId
    var name: Text

    init(id: CustomerId, name: Text) {
        this.id = id
        this.name = name
    }

    func rename(newName: Text) {
        this.name = newName
    }
}
```

<Note>
  In v0.1, only `value` and `object` types can declare contract conformance. Conformance must be declared at the type definition site — there are no retroactive or extension conformances in this version.
</Note>

## `enum` Declarations

An `enum` defines a closed set of named cases. Use `enum` when a concept has a fixed, known set of states or categories.

```kairo theme={null}
public enum OrderStatus {
    Pending
    Confirmed
    Shipped
    Delivered
}
```

Enum cases are referenced using the type name as a qualifier:

```kairo theme={null}
let status: OrderStatus = OrderStatus.Pending
```

## Generics and Constraints

Kairo supports generic type parameters using angle-bracket syntax. Constrain a type parameter by naming a contract it must satisfy:

```kairo theme={null}
public value Wrapper<T> {
    inner: T
}

public func findFirst<T: Named>(items: List<T>): T? {
    // ...
}
```

The constraint `T: Named` means the type argument must conform to the `Named` contract.

## `Result<T, E>` — Outcome Type

`Result<T, E>` is the standard way to represent an operation that can either succeed with a value of type `T` or fail with an error of type `E`. It is part of the Core prelude and available without import.

```kairo theme={null}
public enum ValidationError {
    EmptyName
    NameTooLong
    InvalidCharacters
}

public func validateName(input: Text): Result<Text, ValidationError> {
    if input.isEmpty() {
        return Result.failure(ValidationError.EmptyName)
    }
    return Result.success(input)
}
```

Inspect a `Result` using `.isSuccess`, `.isFailure`, `.value`, and `.error`:

```kairo theme={null}
let outcome = validateName(input)

match outcome.isSuccess {
    true {
        let validName = outcome.value
        // use validName
    }
    false {
        let err = outcome.error
        // handle err
    }
}
```

<Warning>
  Accessing `.value` on a failed `Result`, or `.error` on a successful one, is a **fault** — an unexpected runtime error that terminates the current execution boundary. Always check `.isSuccess` before accessing `.value` or `.error`.
</Warning>

See [Error Handling](/language/error-handling) for full coverage of `Result`, faults, and error-type design.
