E06132: a collection cannot carry a type invariant: its only usable constraints are whole-container predicates ('contains'), which are 'require' preconditions, and a mutating operator would re-validate on every '+=' - so a mutation could break it; constrain the ELEMENT type instead ('List of MyConstrainedElement'), which holds for every element however the collection is assembled
What went wrong
A collection cannot carry a type invariant.
The only constraints usable on a container are whole-container predicates such as 'contains' - and those are 'require' preconditions, not type constraints. A mutating operator would have to re-validate the invariant on every '+=', so any mutation could silently break it.
How to fix it
Constrain the ELEMENT type instead, then build the collection from it (the [EXAMPLE] section below: a 'Tag' String constrained to match /^[a-z]+$/, and a List of Tag).
The invariant then holds for every element, however the collection is assembled.
Rationale
A constraint is a promise about a value that holds for the whole life of that value. A container's contents change after construction, so a container-level promise cannot be kept without re-checking on every mutation. Constraining the element makes the promise hold by construction.
Common causes
- Trying to constrain 'List of X' rather than X
- Expecting a size or emptiness constraint on a collection type
- Confusing 'constrain as' (a type invariant) with 'require' (a precondition)
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E06132: a collection cannot carry a type invariant: its only usable constraints are whole-container predicates ('contains'), which are 'require' preconditions, and a mutating operator would re-validate on every '+=' - so a mutation could break it; constrain the ELEMENT type instead ('List of MyConstrainedElement'), which holds for every element however the collection is assembled
#!ek9 defines module error.e06132.bad defines type //The RIGHT tool: constrain the ELEMENT, then hold a collection of it. The guarantee holds for //every element however the list is assembled. Tag as String constrain as matches /^[a-z]+$/ //The wrong tool: a constrained collection. 'List of String' can never be unset, so the //constrained type has no unset state to borrow. Tags as List of String constrain as contains "req" //Same for any other parameterised generic. Lookup as Dict of (String, Integer) constrain as contains "req"
Fixed: Constrain the ELEMENT type, then hold a collection of it
#!ek9 defines module error.e06132.good defines type Tag as String constrain as matches /^[a-z]+$/ defines function tags() <- rtn as List of Tag: [Tag("req"), Tag("opt")]