Skip to content

Section 24: Optional Values and Null Safety

TECHSPEC-25 — Section 24 · Version 0.1 · Status: Initial Draft

Numbering note: this is file TECHSPEC-25.md but it contains Section 24 of the specification. File numbers and section numbers diverge from TECHSPEC-23 onward; neither has been renumbered. See the specification index and audit AUDIT-001 in reports/documentation-audit.md for details.

Status: draft. This section is an Initial Draft (Section 57 is a Working Register). It describes intended or proposed behavior, not a finalized, implemented language rule. Do not treat examples here as normative.

1. Null Safety Philosophy

The language must make the absence of a value explicit.

A variable must never unexpectedly contain a missing or null value when its declared type does not permit one.

The compiler must prevent code from treating a potentially absent value as though it were guaranteed to exist.

2. Optional Types

The language uses Optional<T> to represent a value that may or may not exist.

Example:

LET username: Optional<String> = NONE
LET accountName: Optional<String> = SOME("Adam")

Rules: - Optional<T> contains either SOME(value) or NONE. - A value inside Optional<T> must match the declared type. - NONE cannot be assigned to a non-optional variable. - Optional values must be handled before their contents can be used. - The compiler must reject unchecked access to optional contents.

3. Checking Optional Values

Optional values must be checked explicitly.

Example:

IF username IS SOME:
    LET name: String = username.VALUE
ELSE:
    RETURN ERROR(MissingUsername)

Rules: - The compiler must recognize when an optional value has been checked. - Accessing .VALUE is permitted only when the compiler can establish that the value is present. - A check in one execution path must not be assumed valid in another. - Changes to the underlying optional value invalidate previous presence checks.

4. Pattern Matching

Optional values may be handled using exhaustive pattern matching.

Example:

MATCH username:
    SOME(value):
        PRINT(value)
    NONE:
        PRINT("No username available")

Rules: - Both SOME and NONE must be handled unless the function explicitly handles the remaining case. - The compiler must reject incomplete exhaustive matches. - Values extracted from SOME receive their declared inner type. - Pattern matching must not silently discard possible cases.

5. Optional Function Returns

Functions may return optional values when absence is an expected outcome rather than an error.

Example:

FUNCTION findUser(id: Integer) -> Optional<User>
    EFFECTS: READ DATABASE

    // Returns NONE when no matching user exists.
END FUNCTION

Rules: - NONE represents an absent result, not necessarily a failure. - Operational failures must use Result<T, E>. - Functions must not use optional returns to conceal unexpected failures. - Callers must handle the possibility of absence.

6. Optional Values and Result Types

Optional<T> and Result<T, E> serve different purposes.

  • Optional<T> represents a value that may not exist.
  • Result<T, E> represents an operation that may succeed or fail.

An operation may need to represent both possibilities:

Result<Optional<User>, DatabaseError>

This means: - SUCCESS(SOME(user)): The operation succeeded and found a user. - SUCCESS(NONE): The operation succeeded but found no user. - ERROR(DatabaseError): The operation failed.

These meanings must remain distinct.

7. Prohibited Behavior

The language must reject: - Assigning NONE to a non-optional variable. - Accessing optional contents without establishing presence. - Silently converting optional values into ordinary values. - Ignoring an absent value when the function requires it to be handled. - Treating absence as an operational failure without an explicit conversion.

8. Compiler and Runtime Responsibilities

The compiler and runtime must: - Track optional types. - Require safe handling before accessing optional contents. - Verify exhaustive optional pattern matching. - Prevent unchecked optional access. - Preserve optional semantics during code generation. - Report the exact location of unsafe access. - Distinguish absence from operational failure.

9. Design Goal

Missing values must be visible in the program's types and control flow.

An AI agent must never be able to assume that a value exists merely because it expects one to exist.


Source file: TECHSPEC-25.md (preserved in source-original/LANG/). See the specification index, the glossary, and the cross-reference index.