> ## 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 Built-in Types and Collections Reference

> Reference for all built-in Kairo types: scalar types, temporal types, collection types, the Result<T,E> outcome type, and nullable T? with usage notes.

Kairo ships with a rich set of built-in types that cover everyday domain modelling needs without requiring third-party libraries. This page is the complete reference for scalar types, temporal types, collections, the `Result<T, E>` outcome type, and nullable `T?` — including usage notes, API surface, and examples.

## Scalar Types

Scalar types represent single, indivisible values. All scalar types are value-like and can be stored inside a `value` declaration.

| Type      | Description                 | Notes                             |
| --------- | --------------------------- | --------------------------------- |
| `Bool`    | Boolean value               | Literals: `true`, `false`         |
| `Text`    | Primary text / string type  | Use `Text`, not `String`          |
| `Int32`   | 32-bit signed integer       | Default type for integer literals |
| `Int64`   | 64-bit signed integer       | Requires explicit annotation      |
| `Decimal` | Arbitrary-precision decimal | Default for fractional literals   |
| `Float64` | IEEE 754 64-bit float       | Requires explicit annotation      |

<Note>
  Kairo uses `Text` as the canonical string type — there is no `String`. Similarly, `Decimal` is the default for fractional numbers like `9.99`; only use `Float64` when you have a specific reason to work with binary floating-point arithmetic.
</Note>

```kairo theme={null}
let greeting: Text = "Hello, Kairo"
let count: Int32 = 42
let bigNumber: Int64 = 9_000_000_000
let price: Decimal = 19.99
let ratio: Float64 = 3.14159
let active: Bool = true
```

## Temporal Types

Kairo provides first-class temporal types for dates, times, and durations. All temporal types are value-like.

| Type       | Description                                    |
| ---------- | ---------------------------------------------- |
| `Date`     | A calendar date (year, month, day)             |
| `Time`     | A time of day (hour, minute, second)           |
| `DateTime` | Combined date and time, without timezone       |
| `Instant`  | A point in time on the UTC timeline            |
| `Duration` | A span of time (hours, minutes, seconds, etc.) |

```kairo theme={null}
let today: Date = Date { year: 2025, month: 6, day: 1 }
let now: Instant = Instant.now()
let window: Duration = Duration { hours: 24 }
```

## Collection Types

Kairo provides immutable and mutable variants of three standard collection shapes. All collection types are generic.

### 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 collection that supports add/remove |
| `MutableMap<K, V>` | Key-value mapping that supports put/remove         |

```kairo theme={null}
var tags: MutableList<Text> = MutableList()
tags.add("billing")
tags.add("urgent")
tags.add("q2")

var items: MutableList<Text> = MutableList()
items.add("first")
items.add("second")
```

<Tip>
  Prefer immutable collections (`List`, `Set`, `Map`) wherever possible. Switch to the mutable variants only when you need to build up a collection incrementally.
</Tip>

## `Result<T, E>`

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

`E` must be a value-like type (a `value` declaration or scalar).

### Construction

<ParamField body="Result.success(value)" type="Result<T, E>">
  Wraps a successful outcome. Pass the success value as the argument.
</ParamField>

<ParamField body="Result.failure(error)" type="Result<T, E>">
  Wraps a failure outcome. Pass an instance of the error type `E` as the argument.
</ParamField>

### Properties

<ResponseField name="isSuccess" type="Bool">
  `true` when the result holds a success value.
</ResponseField>

<ResponseField name="isFailure" type="Bool">
  `true` when the result holds a failure value.
</ResponseField>

<ResponseField name="value" type="T">
  The success value. Accessing this property when `isFailure` is `true` is a fault.
</ResponseField>

<ResponseField name="error" type="E">
  The failure value. Accessing this property when `isSuccess` is `true` is a fault.
</ResponseField>

<Warning>
  Always check `isSuccess` or `isFailure` before accessing `.value` or `.error`. Reading `.value` on a failed result, or `.error` on a successful result, is a runtime fault.
</Warning>

```kairo theme={null}
public value ParseError {
    message: Text
}

public value EmailAddress {
    address: Text

    type func parse(input: Text): Result<EmailAddress, ParseError> {
        if input.contains("@") {
            return Result.success(EmailAddress { address: input })
        }
        return Result.failure(ParseError { message: "Missing @ symbol" })
    }
}

let outcome: Result<EmailAddress, ParseError> = EmailAddress.parse("user@example.com")

if outcome.isSuccess {
    Pulse.Console.out.writeLine(outcome.value.address)
} else {
    Pulse.Console.error.writeLine(outcome.error.message)
}
```

## Nullable Types — `T?`

By default, every type in Kairo is non-null. To allow a value to be absent, append `?` to the type name.

**Rules:**

* `T?` is the only nullable form. Double-nullable `T??` is invalid and a compile error.
* The null literal is `null`.
* You must handle the nullable case explicitly — there is no automatic null propagation.

```kairo theme={null}
let middleName: Text? = null
let optionalId: Int32? = 42

if middleName != null {
    Pulse.Console.out.writeLine(middleName)
}
```

```kairo theme={null}
public value UserProfile {
    displayName: Text
    bio: Text?       // bio is optional
}

let profile: UserProfile = UserProfile { displayName: "Ada", bio: null }
```

<Warning>
  `T??` is not valid Kairo. If you find yourself wanting a nullable-of-nullable, consider whether `Result<T?, E>` or a dedicated `value` type better models your domain.
</Warning>

## Type Notes

| Topic                  | Guidance                                                                                                                        |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `Text` vs `String`     | Always use `Text`. The name `String` does not exist in Kairo.                                                                   |
| `Decimal` vs `Float64` | Use `Decimal` for money, quantities, and domain values. Use `Float64` only for scientific or performance-sensitive computation. |
| Integer literals       | Unadorned integer literals (`42`) are inferred as `Int32`. Annotate explicitly for `Int64`.                                     |
| Fractional literals    | Unadorned fractional literals (`9.99`) are inferred as `Decimal`. Annotate explicitly for `Float64`.                            |
