Skip to content

Section 38: Generics and Parametric Polymorphism

TECHSPEC-38 — Section 38 · Version 0.1 · Status: Initial Draft

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. Generics Philosophy

Generics allow functions, types, and collections to operate on multiple compatible types without duplicating implementations.

The language must support reusable code while preserving strict type safety and contract verification.

Generic flexibility must never mean accepting arbitrary values without defined constraints.

2. Generic Functions

Functions may declare type parameters.

Example:

FUNCTION identity<T>(value: T) -> T
    ENSURES: result == value

    RETURN value
END FUNCTION

Rules: - Generic parameters must be explicitly declared. - Type arguments must satisfy all declared constraints. - Generic return types must be predictable. - Type inference may be used when exactly one valid interpretation exists. - Ambiguous type inference must produce a compiler error.

3. Generic Types

Types may declare parameters that determine the types of their contents.

Example:

TYPE Container<T>:
    value: T
END TYPE

Generic types may be used in: - Structures. - Enumerations where supported. - Collections. - Results. - Optional values. - References. - Function parameters and returns.

Rules: - Generic parameters must have defined scope. - Type substitution must preserve type constraints. - Invalid type arguments must be rejected. - Generic types must not bypass ownership or mutability rules.

4. Type Constraints

Generic parameters may declare requirements.

Example:

FUNCTION findMaximum<T: Comparable>(
    values: List<T>
) -> Optional<T>

Rules: - Constraints must identify required operations or properties. - A generic implementation may use only capabilities guaranteed by its constraints. - Constraints must be checked by the compiler. - Missing required capabilities must produce a compiler error. - Constraints must not be inferred from accidental implementation details.

5. Interfaces and Traits

The language should support explicit interfaces or traits describing shared behavior.

Example:

INTERFACE Comparable:
    FUNCTION compareTo(other: SELF) -> Integer
END INTERFACE

Rules: - Interface requirements must have explicit signatures. - Implementations must satisfy required signatures and contracts. - Missing methods must produce compiler errors. - Contract compatibility must be checked where possible. - Implementing an interface must not imply stronger guarantees than its declared requirements. - Interface evolution must follow language compatibility rules.

6. Generic Contracts

Generic functions and types must support contracts.

Rules: - Preconditions must apply to all valid type substitutions. - Postconditions must remain valid for all supported type arguments. - Generic constraints must provide sufficient information to establish required guarantees. - Runtime contract checks must preserve the concrete type information needed for evaluation. - A contract that cannot be established must not be reported as proven.

7. Generic Collections

Standard collections must use the generic type system.

Examples:

List<Integer>
Map<String, Decimal>
Set<UserIdentity>
Optional<Account>
Result<User, DatabaseError>

Rules: - Collection element types must be enforced. - Generic collections must preserve ownership and mutability rules. - Incompatible values must be rejected. - Collection operations must preserve their documented type guarantees.

8. Variance

Generic types may require variance rules.

The language must explicitly define:

  • Covariance.
  • Contravariance.
  • Invariance.

Rules: - Variance must be declared or determined through formally specified rules. - Unsafe substitutions must be rejected. - Mutable generic containers must not permit type substitutions that violate element safety. - The compiler must explain variance-related incompatibilities.

The exact variance model remains to be specified.

9. Monomorphization and Runtime Representation

The implementation must define how generic code is represented during compilation and execution.

Potential strategies include: - Monomorphization. - Type erasure. - Runtime type metadata.

Rules: - Implementation strategy must not change source-language semantics. - Runtime type information must follow the reflection specification. - Code generation must preserve generic contracts. - Performance characteristics must be documented. - Different execution targets must preserve compatible behavior.

The MVP may use a simpler generic implementation strategy before advanced optimization is introduced.

10. Compiler and Runtime Responsibilities

The compiler and runtime must: - Resolve generic parameters. - Validate type constraints. - Check interface implementations. - Enforce generic contracts. - Preserve type safety during substitution. - Reject ambiguous inference. - Generate consistent executable representations. - Report generic type errors precisely.

11. Verification Limitations

Generic code may be reusable across many types, but verification must establish the guarantees that actually apply to each supported substitution.

Verification reports must distinguish: - Generic constraints declared. - Constraints statically satisfied. - Generic implementation checked. - Contract properties proven. - Runtime checks executed. - Unsupported or unverified substitutions.

A generic function must not be considered universally correct merely because it compiles for one type.

12. Design Goal

An AI agent must be able to write reusable, strongly typed code without sacrificing contracts, ownership, or verification.

Generic abstractions must preserve guarantees rather than hide uncertainty behind flexible type parameters.


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