Types and OOP Generics

Generics

Generics let Klyn preserve strong typing across reusable containers and abstractions. They are central to the collection APIs and to user-defined types that must carry a caller-chosen element type.

Generic Type Parameters
public interface Collection<T = Double>:
    public add(item as T) as Void

Generic parameters appear between angle brackets and can be referenced throughout the type body.

Instantiating Generic Types
names = ArrayList<String>()
scores = Map<String, Int>()

Explicit type arguments are especially valuable when the initial state is empty and therefore cannot drive inference on its own.

Default Generic Arguments
public class NDArray<T extends AbstractNumber = Double>:
    pass

Defaults let a generic API stay concise when one concrete type is overwhelmingly common.

Constraints
public class NDArray<T extends AbstractNumber = Double>:
    pass

A constraint restricts which types may be substituted for the generic parameter.

Inference from Literal Content
[10, 20, 30]                    # ArrayList<Int>
ImmutableList([10, 20, 30])   # ImmutableList<Int>
{"a": 1, "b": 2}               # Map<String, Int>
(1, 2, 3)                      # Tuple<Int, Int, Int>

Literal inference removes boilerplate, but explicit annotations remain the better choice when the surrounding API should communicate a stable type contract.

Klyn now separates immutable homogeneous sequences from tuples: ImmutableList<T> is exposed through IList<T>, while Tuple<...Ts> is positional and heterogeneous.

Generic Types and Reflection
metadata = type(List<Int>)
print(metadata.isGenericInstantiation)
print(metadata.genericParameterCount)

Generic instantiations are visible through reflection, which is useful for tooling and typed framework code.