Start Here

Coming From Other Languages

Map your existing knowledge of Python, JavaScript, Java, or Rust to the concepts here, including features that are intentionally omitted.

Outcome: Translate your existing programming habits into the patterns used here, and identify which patterns are intentionally omitted.

Prerequisite: Ability to read code in at least one other language. No prior experience with this language is required.

Start from what transfers unchanged

Much of the syntax will look familiar. Values, names, functions, conditionals, loops, and collections perform recognizable roles, while the checker explicitly highlights key differences. You should be able to understand what the code snippet below does before learning every detail.

TOPAZ
record Task {
    title: string,
    minutes: int
}

function totalMinutes(tasks: Array<Task>) -> int {
    let mut total = 0
    for task in tasks {
        total = total + task.minutes
    }
    total
}

If you have written Python, JavaScript, Java, or Rust, you can already determine what this code does. That is the rationale for starting here. The key differences worth noting are few, as outlined below.

Four differences that actually matter

Mutation is opt-in. A plain let binding cannot be reassigned. Declaring let mut specifies that reassignment is intended. Languages where variables are mutable by default often require examining more of a function to determine which names change. Here, the declaration answers that question.

Recoverable failure is a value. There are no exceptions to catch. A function with a recoverable failure returns a Result, which the caller either handles or propagates using ?. The call boundary carries the failure structure instead of requiring you to infer it from a function body or exception convention. Runtime faults remain a separate, non-recoverable concern.

Absence is represented in the type. Standard optional values use Option<T>. External nullable data uses T | null, keeping the two models distinct. In both cases, the checker requires handling the absent case before treating the value as present.

Host authority has an explicit boundary. File and I/O operations are accessible only through the selected host or product profile, while web products receive only declared, bounded capabilities. A function signature indicates data and recoverable failure. Imports, package configuration, and the selected profile complete the authority scope. Reading a Real File uses all of these mechanisms.

What is deliberately absent

Understanding which patterns are omitted helps avoid reaching for unmapped habits early on.

There are no class hierarchies or inheritance structures. Data shapes are records, and behavior lives in functions operating on them. If your instinct is to design with base classes and overrides, model with records and explicit functions instead.

There is no runtime reflection over your program, no dynamic dispatch via protocol tables, and no row polymorphism. Details on deferred capabilities are in Records & Nominal Data.

Implicit conversions between numeric types are not supported. An int does not convert to a float for convenience in surrounding expressions.

These design boundaries are intentional. They keep critical choices visible in code declarations and configuration without assuming a function signature captures every host interaction.

A translation table for the first hour

A dict, Map, or HashMap maps to a collection, detailed in Collections & Comprehensions. A data-only class often maps to a record. Define interface boundaries using explicit function signatures. Use a static protocol when a generic contract requires one, without runtime dynamic dispatch. Recoverable try/except logic maps to returning a Result. Standard optional results use Option. External nullable data uses T | null, with the checker maintaining an explicit distinction between them.

Try this

Consider a function that looks up a task by title and might not find one. Before reading the answer, decide what its return type should be.

Answer

An Option of a task, rather than a task type alone. A missing item is an ordinary outcome of a lookup operation rather than an error, so it is expressed in the type as absence. A Result would be appropriate if the lookup operation itself could fail, such as when reading from a file. Distinguishing between absence and failure is an explicit choice required by this language, and defining it in the signature saves every caller from guessing.

Ready to continue when

You can list the four key differences, identify which habits from previous languages are omitted here, and choose between absence and failure for a function you are about to write.

Work through the course starting at First Program if you have not done so, or move directly to Syntax at a Glance.