How must constructor argument types match generic type parameters?
← Generics · Ref: Q644
When a generic type has an inferred constructor, the constructor parameter types must match the type parameters in both type and order. 'MyType of type (A, B)' must have constructor 'MyType(a as A, b as B)' with A first and B second.
ORDER MATTERS
For 'Pair of type (A, B)', the constructor must be:
Pair(first as A, second as B)
Not 'Pair(first as B, second as A)' which reverses the types.
TYPE MATCHING
Each constructor parameter must use the corresponding type parameter:
Position of type T Position(x as T) // T matches the type parameter
WHY THIS RESTRICTION
The compiler uses the constructor to infer type arguments. If 'Pair("hello", 42)' is written, the compiler maps argument 1 to A (String) and argument 2 to B (Integer). The positional correspondence must be unambiguous.
See Q642 for constructor inference. See Q643 for two-constructor requirement. See Q645 for public constructor requirement.
Example
defines module qa.genericsdeep.constructorargtypes defines class <?- Single-param: constructor argument type matches type parameter T. -?> Wrapper of type T wrapped as T? Wrapper() as pure wrapped :=? T() Wrapper() as pure -> item as T wrapped :=? item unwrap() <- rtn as T: T() rtn :=? T(wrapped) default operator ? <?- Multi-param: constructor argument order matches type parameter order. (A, B) maps to (first, second) positionally. -?> Entry of type (A, B) first as A? second as B? Entry() as pure first :=? A() second :=? B() Entry() as pure -> a as A b as B first :=? a second :=? b getFirst() <- rtn as A: A() rtn :=? A(first) getSecond() <- rtn as B: B() rtn :=? B(second) default operator ? defines program ConstructorArgTypeDemo() stdout <- Stdout() // === SINGLE PARAM INFERENCE === intWrap <- Wrapper(100) stdout.println(`Int wrapper: ${intWrap?}`) strWrap <- Wrapper("text") stdout.println(`String wrapper: ${strWrap?}`) // === MULTI PARAM INFERENCE (positional) === record <- Entry("id-001", 42) stdout.println(`Entry set: ${record?}`) first <- record.getFirst() if first? stdout.println(`First: ${first}`)
Common mistakes
E06050 — Constructor parameter types must match the type parameters in the same positional order. For 'Entry of type (A, B)', the first constructor parameter must be type A and the second must be type B. Reversing them breaks the positional correspondence the compiler uses for type inference. See ek9 -h E06050 for details.
Incorrect:
Entry of type (A, B) first as A? second as B? default Entry() as pure Entry() as pure -> a as B b as A
Correct:
Entry of type (A, B) first as A? second as B? Entry() as pure first :=? A() second :=? B() Entry() as pure ->
Other ways to ask this
- What is E06050 constructor argument must match parametric types?
- Why must constructor parameter order match type parameter order?
- How does EK9 validate generic constructor signatures?
Coming from another language?
Java: no constructor-to-type-param mapping (erasure). C++: template argument deduction from constructor (C++17 CTAD). Rust: no constructor syntax, uses 'new' pattern. Go: no constructor, zero-value + explicit init. Kotlin: constructor infers from usage like Java. EK9: strict positional mapping between type params and constructor params.
Keywords: order, match, inference, E06050, type-parameter, generic, type, constructor, constant, argument, positional