E07845: a for-range needs an ordered, steppable type - this type has no ordering and no step
What went wrong
A for-RANGE was written over a type that has no ordering and no step, so there is no sequence for the loop to walk. The common case is a function: 'for x in fn1 ... fn2'.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 64 (How do I write a for loop over a range of numbers?)
- ek9 -q 1149 (Iterate from 0 to 20 with a step of 5 using for-range wit...)
- ek9 -q 89 (How do I use streams and stream pipelines in EK9?)
What can be ranged
Any type providing an ordering ('<=>'), a step ('++'/'--') and a copy constructor (the loop makes its counter with one, E08272) - which includes YOUR OWN types, not just built-ins. The [EXAMPLE] below ranges over Integer and Character, and over a user type, Step.
So this error is not "only built-ins can be ranged". It means the type could never provide those operators. A user type that is simply MISSING one reports E07620 instead, because there adding it is the fix.
[WHY THIS IS NOT "ADD AN OPERATOR"] A for-range drives its counter with '<=>' and a copy constructor, plus '++'/'--' or '+=' when a 'by' step is given. A previous version of this check reported "operator '<=>' is required", which invites you to add that operator - but a function cannot declare operators at all, so no amount of adding fixes it. The shape simply is not meaningful: two functions do not describe a range, because there is no sequence of values between them.
[THIS IS NOT "FUNCTIONS CANNOT BE STREAMED"] Functions stream perfectly well - what cannot happen is ranging BETWEEN two of them. Hold them in a collection and the collection is what gets iterated (one of the fixes in the [EXAMPLE] below streams a List of functions).
How to fix it
- If you meant to process several functions, put them in a collection and 'cat' it, as above
- If you meant a numeric or ordered range, use a type that has an ordering and a step - Integer, Character, Date, Time, Duration and similar
- If you meant to call the functions, call them rather than ranging them
Common causes
- Reaching for 'for ... in a ... b' when the intent was to iterate a collection, which is 'for item in collection' or 'cat collection'
- Confusing 'a ... b' (a range between two values) with iterating a collection, which needs 'for item in collection' or 'cat collection'
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E07845: a for-range needs an ordered, steppable type - this type has no ordering and no step
#!ek9 defines module error.e07845.bad defines function low() as pure -> text as String <- rtn as String: text high() as pure -> text as String <- rtn as String: text printSteps() stdout <- Stdout() //A function has no order and no next value for step in low ... high stdout.println("step")
Fixed: Range over an ordered, steppable type
#!ek9 defines module error.e07845.good defines program PrintSteps() stdout <- Stdout() //Integer and Character are ordered and steppable for step in 1 ... 3 stdout.println($step) for letter in 'a' ... 'c' stdout.println($letter)
Fixed: To process several functions, stream a collection of them
#!ek9 defines module error.e07845.good.stream defines function Shout() as abstract -> text as String <- rtn as String? loud() is Shout -> text as String <- rtn as String: text.upperCase() quiet() is Shout -> text as String <- rtn as String: text.lowerCase() applyIt() -> shout as Shout <- rtn as String: shout("Hello") defines program //To process several functions, stream a collection of them ShoutAll() stdout <- Stdout() handlers as List of Shout: [loud, quiet] cat handlers | map with applyIt > stdout
Fixed: Or a type of your own that is ordered and steppable
#!ek9 defines module error.e07845.good.user defines class //Ordered ('<=>'), steppable ('++' and '--'), and copyable (the copy constructor) Step position as Integer? default private Step() as pure Step() as pure -> initial as Integer position :=? Integer(initial) Step() as pure -> other as Step position :=? Integer(other.position) operator <=> as pure -> other as Step <- rtn as Integer: position <=> other.position operator #? as pure <- rtn as Integer: #?position operator $ as pure <- rtn as String: $position operator ++ position++ operator -- position-- override operator ? as pure <- rtn as Boolean: position? defines program PrintSteps() stdout <- Stdout() for step in Step(1) ... Step(3) stdout.println($step)