docs / guide / The Cajeta Guide

Chapters — 9. Type kinds
  1. Introduction
  2. 0. Introduction
  3. 1. Installation
  4. 2. Kick the tires
  5. 3. Your first project
  6. 4. Running your application
  7. 5. Debugging
  8. 6. Keywords
  9. 7. Comments
  10. 8. Native types
  11. 9. Type kinds
  12. 10. Allocation
  13. 11. Ownership & borrowing
  14. 12. Control flow
  15. 13. Strings & formatting
  16. 14. Templates & wildcards
  17. 15. Lambdas & captures
  18. 16. Operator overloading
  19. 17. Inheritance
  20. 18. Annotations & synthesis
  21. 19. DI & aspects
  22. 20. Error handling
  23. 21. Reflection
  24. 22. Differentiation
  25. 23. Code coverage
  26. 23. Profiling
  27. 24. Notebooks
  28. 25. Writing XPU Kernels

09 — Type kinds

Six type kinds ship today: class, interface, enum, record, view, and annotation; a method becomes a GPU kernel with @Kernel. structure is a reserved word with no syntax yet.

class

The one aggregate type. Whether an instance is a reference or a value is decided at the construction site (heap vs stack — chapter 10), not in the declaration.

public class Circle {
    public float64 radius;

    public Circle(float64 radius) {
        this.radius = radius;
    }

    public float64 area() { return 3.14159 * radius * radius; }
}

Tour: ClassesDemo.cajeta.

interface

Method contracts, no state, no default methods. Dispatch is virtual through the implementing class.

public interface Shape {
    float64 area();
}

public class Disc implements Shape {
    public float64 r;
    public Disc(float64 r) { this.r = r; }
    public float64 area() { return 3.14159 * r * r; }
}

enum

A fixed set of named constants. An enum value casts to int32 — (int32) Color.BLUE is 2, its ordinal.

public enum Color {
    RED,
    GREEN,
    BLUE
}

record

A value type: a flat bundle of fields with no per-instance header and no vtable — the in-memory value is exactly the field bytes (records spec §1.4). Assignment copies, == compares field-by-field (structural equality), and fields are immutable unless a field opts in with mut.

public record Tick {
    mut float64 price;
    int32 volume = 1;
}

public class TickDemo {
    public void demo() {
        Tick a = Tick { price: 2.5, volume: 4 };  // labeled binding
        Tick b = Tick { 2.5, 4 };                 // positional, declared order
        boolean same = a == b;                    // structural equality: true
        Tick c = Tick { price: 9.0 };             // volume fills from its default
        Tick d = a.with(price: 3.0);              // copy-with; a is untouched
        a.price = 3.5;                            // mut field writes in place
    }
}

Construction is the aggregate initializer, labeled or positional (never mixed in one initializer); a field with a declared default may be omitted — in the positional form, only trailing fields. A record can also declare an ordinary constructor and be built with heap / stack like a class. Writing a non-mut field is a compile error — use with(...), which returns a copy with the named fields replaced.

Records may extends another record: static, non-virtual inheritance — derived adds fields and methods but cannot override. What a record cannot have: virtual or abstract methods, implements, or reference-type fields (a class field, including String, is a compile error). A class may hold record fields; never the reverse.

Records reflect like classes: Tick.class enumerates field names, types, offsets, and sizes (chapter 21). One gap today: T.class inside a template body does not yet resolve the substituted type argument — that applies to any type argument, not just records.

The stdlib dogfoods it: Color (cajeta.math.Color) is a record over four float32 channels.

view

A typed, zero-copy overlay onto a byte buffer — no allocation, no object graph. Layout is byte-exact and declared; endianness is @BigEndian / @LittleEndian / host by default. Views cannot hold class references or implement interfaces (Views.md).

@BigEndian
public view PacketHeader {
    int32 magic;
    int16 version;
    int16 flags;
}

Tour: ViewsDemo.cajeta.

annotation

Declares an annotation type; apply it with @Name(...). Annotations drive code synthesis (@Builder), DI (@Inject, @Singleton), and reflection.

public annotation Todo {
    String value;
}

@Todo(value = "cache the result")
public class Planner {
    public int32 estimate() { return 3; }
}

Tour: AnnotationsDemo.cajeta.

@Kernel functions

@Kernel on a static method compiles it for the GPU (or the CPU fallback) — the same source targets NVPTX, AMDGPU, SPIR-V, or host SIMD.

import cajeta.xpu.KernelBuffer;
import cajeta.xpu.KernelThread;

public final class Kernels {
    // y[i] = a*x[i] + y[i]
    @Kernel
    public static void saxpy(KernelBuffer<float32> y, KernelBuffer<float32> x,
                             float32 a, uint32 n) {
        uint32 i = KernelThread.globalIdX();
        if (i < n) { y[i] = a * x[i] + y[i]; }
    }
}

Tour: XpuTour.cajeta.

Reserved: structure

structure has no declaration syntax — writing one is a parse error today.

Next: Allocation.

Source: docs/guide/09-type-kinds.md · 2 min · 431 words