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.