Skip to content

Data Types ​

Kettle has a rich set of data types for structuring your programs.

Records ​

Records are named collections of fields:

kettle
type Point = record
  x: Float
  y: Float
end record

type Person = record
  name: String
  age: Int
end record

Creating Records ​

kettle
origin = Point { x: 0.0, y: 0.0 }
alice = Person { name: "Alice", age: 30 }

Accessing Fields ​

Use dot notation:

kettle
print(alice.name)           -- "Alice"
print(to_string(origin.x))  -- "0.0"

Updating Records ​

Create a new record with some fields changed:

kettle
moved = Point { x: origin.x + 1.0, y: origin.y }

Variants ​

Variants (also called sum types or tagged unions) represent values that can be one of several forms:

kettle
type Shape = variant
  Circle(radius: Float)
  Rectangle(width: Float, height: Float)
  Triangle(base: Float, height: Float)
end variant

Creating Variants ​

kettle
c = Circle(5.0)
r = Rectangle(10.0, 20.0)

Pattern Matching ​

Use match to handle each case:

kettle
fn area(shape: Shape) -> Float
  match shape
    Circle(r) -> 3.14159 * r * r
    Rectangle(w, h) -> w * h
    Triangle(b, h) -> 0.5 * b * h
  end match
end fn

Unit Variants ​

Variants can have no data:

kettle
type Direction = variant
  North
  South
  East
  West
end variant

fn opposite(d: Direction) -> Direction
  match d
    North -> South
    South -> North
    East -> West
    West -> East
  end match
end fn

Option and Result ​

Option Type ​

Option[T] represents a value that might be absent:

kettle
type Option[T] = variant
  Some(value: T)
  None
end variant

Use it instead of null:

kettle
fn find_index(lst: List[Int], target: Int) -> Option[Int]
  for (item, idx) in enumerate(lst) with result = None
    match item == target
      True -> Some(idx)
      False -> result
    end match
  end for
end fn

fn main() -> Unit using file_io
  numbers = [10, 20, 30, 40]
  match find_index(numbers, 30)
    Some(i) -> print("Found at index ${to_string(i)}")
    None -> print("Not found")
  end match
end fn

Result Type ​

Result[T, E] represents success or failure:

kettle
type Result[T, E] = variant
  Ok(value: T)
  Err(error: E)
end variant

Use it for operations that can fail:

kettle
fn parse_positive(s: String) -> Result[Int, String]
  match to_int(s)
    Some(n) ->
      match n > 0
        True -> Ok(n)
        False -> Err("Must be positive")
      end match
    None -> Err("Invalid number: ${s}")
  end match
end fn

Tuples ​

Tuples group values of different types:

kettle
pair = (1, "hello")
triple = (True, 3.14, "test")

-- Destructuring
(flag, value, label) = triple

Lists ​

Lists hold multiple values of the same type:

kettle
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Carol"]
empty: List[Int] = []

Accessing Elements ​

Use get_at to access elements by index (returns Option since index might be out of bounds):

kettle
numbers = [10, 20, 30, 40]

-- get_at(index, list) - pipe-friendly
first = numbers | get_at(0)   -- Some(10)
third = numbers | get_at(2)   -- Some(30)
oob = numbers | get_at(99)    -- None (out of bounds)

-- Handle the Option
match numbers | get_at(0)
  Some(n) -> print("First: ${to_string(n)}")
  None -> print("List is empty")
end match

For convenience, use head and last:

kettle
first = head(numbers)  -- Some(10)
final = last(numbers)  -- Some(40)

Common Operations ​

kettle
-- Length
len = length(numbers)

-- Append (pipe-friendly)
more = numbers | append(6)

-- Concatenate
all = numbers | concat([6, 7, 8])

-- Transform
doubled = numbers | map(fn(x: Int) -> x * 2)

-- Filter
evens = numbers | filter(fn(x: Int) -> x % 2 == 0)

-- Reduce
total = numbers | fold(0, fn(acc: Int, x: Int) -> acc + x)

Type Annotations ​

While Kettle infers most types, you can add annotations:

kettle
-- Variable annotation
count: Int = 0

-- Function with full annotations
fn add(a: Int, b: Int) -> Int
  a + b
end fn

-- Empty collections need annotations
empty_list: List[String] = []

Next Steps ​