How must constrained type constructors match the parameterising type?
← Generics · Ref: Q651
When a generic type is constrained with 'constrain by', the constraining type's constructors must be present on any type used to parameterise the generic. If the constraining type has a String constructor, any actual type argument must also have a String constructor.
CONSTRUCTOR MATCHING
If Shape has 'Shape(name as String)', then any T used in 'of type T constrain by Shape' must also have a String constructor.
WHY REQUIRED
Generic code may create instances of T using constructors from the constraining type. If the constructor does not exist, the code would fail at instantiation.
CORRECT PATTERN
Ensure subtypes mirror the constructor signatures:
Shape as abstract Shape(n as String) Circle is Shape Circle(n as String) // matches Shape's constructor super(n)
See Q195 for constrain by basics. See Q642 for constructor inference. See Q647 for function constraint limits.
Example
defines module qa.genericsdeep.constraintconstructormatch defines class <?- Abstract base class used as constraint. Has both default and String constructors. -?> Vehicle as abstract vehicleName as String: String() default Vehicle() as pure Vehicle() as pure -> n as String vehicleName :=? String(n) name() as pure <- rtn as String: String(vehicleName) default operator ? <?- Concrete subtype with matching constructors. Both default and String constructors present (matching Vehicle). -?> Truck is Vehicle payload <- Integer() default Truck() as pure Truck() as pure -> n as String super(n) Truck() as pure -> n as String cap as Integer super(n) payload :=? cap override operator ? as pure <- rtn as Boolean: name()? <?- Subtype missing String constructor (for E06130 mutation testing). -?> Bicycle is Vehicle default Bicycle() as pure override operator ? as pure <- rtn as Boolean: name()? <?- Another concrete subtype with matching constructors. -?> Sedan is Vehicle doors as Integer: 4 default Sedan() as pure Sedan() as pure -> n as String super(n) override operator ? as pure <- rtn as Boolean: name()? defines function <?- Constrained generic function. T must be a Vehicle, so T has name() method available. -?> describeVehicle() of type T constrain by Vehicle as open -> item as T <- rtn as String: item.name() defines program ConstraintConstructorDemo() stdout <- Stdout() truck <- Truck("Big Rig") truckDesc <- describeVehicle(truck) stdout.println(`Truck: ${truckDesc}`) sedan <- Sedan("Family Car") sedanDesc <- describeVehicle(sedan) stdout.println(`Sedan: ${sedanDesc}`)
Common mistakes
E50060 — When a generic type is constrained by Vehicle (which has a String constructor), any type used to parameterise it must also have a matching String constructor. Removing the String constructor from Truck while keeping only a non-matching constructor triggers E50060. See ek9 -h E50060 for details.
Incorrect:
Truck() as pure -> cap as Integer payload :=? cap
Correct:
Truck() as pure -> n as String super(n)
E06130 — Bicycle extends Vehicle but is missing the String constructor that Vehicle defines. When describeVehicle (constrained by Vehicle) is parameterised with Bicycle, the compiler detects the missing constructor match and triggers E06130. See ek9 -h E06130 for details.
Incorrect:
bicycle <- Bicycle() bicycleDesc <- describeVehicle(bicycle) stdout.println(`Bicycle: ${bicycleDesc}`)
Correct:
sedan <- Sedan("Family Car") sedanDesc <- describeVehicle(sedan) stdout.println(`Sedan: ${sedanDesc}`)
Other ways to ask this
- What is E06130 constrained type constructor missing?
- Why must constrained generic subtypes have matching constructors?
- How do constructor requirements flow from constraints to subtypes?
Coming from another language?
Java: no constructor inheritance or matching requirement (erasure). C++: concepts can require constructibility. Rust: trait bounds define method requirements, not constructors. Go: no constructor concept. Kotlin: no constructor matching for generics. EK9: constraining type constructors must exist on parameterising type.
Keywords: match, parameter, constructor, E06130, constraint, constant, missing, type-parameter, generic, subtype