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. Their names must not replace a visible nominal type: use a parameter such as T, not String or Type.

Instantiating Generic Types

import klyn.collections

names = ArrayList<String>()
scores = SortedMap<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

import klyn.collections

[10, 20, 30]                  # ArrayList<Int>
s:[10, 20, 30]                # ArrayListSync<Int>
f:[10, 20, 30]                 # Array<Int>
fs:[10, 20, 30]                # ArraySync<Int>
i:[10, 20, 30]                 # ImmutableList<Int>
l:[10, 20, 30]                 # LinkedList<Int>
ls:[10, 20, 30]                # LinkedListSync<Int>
{"a": 1, "b": 2}              # HashMap<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. Collection prefixes are part of that contract: they select the concrete collection generated by the compiler, not a late runtime conversion.

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

A variadic type pack may contain no types. An explicit empty pack does not gain an Object element: Tuple() and () both produce Tuple<>. Default arguments for fixed generic parameters are unchanged.

empty = Tuple()
assert empty.size == 0ul
assert type(empty) == type(())

Generic Types and Reflection

import klyn.collections

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.