E08277: the same variable is read by 'cat' and appended to ('>>' or 'tee') in one stream statement, so the read never reaches the end - input is output; read a copy instead, use '>' to replace it, or collect into a new variable
What went wrong
One stream statement reads a variable with 'cat' and appends to that same variable - with '>>' as its termination, or with a 'tee' stage that has it as its target. It does not matter what the variable is: a List, a Set, a Dict, a PriorityQueue, a JSON - there is one rule and no list of types. The stream pulls from the variable one element at a time while the append keeps adding to it, so the read can never reach the end of what it is reading. GNU cat says the same of a file: "input file is output file". The compiler reports it on the target, by the variable itself and not by its name, so it also finds a source and a target written as 'this.items' and plain 'items' (one property, two spellings), and 'cat first, items >> items' with the variable among several sources.
//'>>' appends to 'scores' while 'cat' is still reading it, so the read can never reach the end. cat scores >> scores
Only '>>' and 'tee' are reported. A '>' fills a fresh collection and swaps it in when the stream is finished, so 'cat items > items' is well defined and is not an error. And a variable held by another object ('other.items') is another variable, even though the property has the same name.
A 'tee' counts at any stage of the pipeline, however long, with a mapper or without, and so does every source of a 'cat a, b, c'. The expression form ('x <- cat items | tee in items | collect as ...') is judged the same way.
Where the compiler cannot see two names for one value - 'alias <- items' then 'cat items >> alias', or one List handed to a function as both its source and its target - the program runs, and the stream stops, before it reads anything, with an Exception whose reason is "<Type> changed while it was being read" ("List changed while it was being read", "Set ...", "Dict ...", "PriorityQueue ...", "JSON ..."): the statement compares the objects it reads with the objects it appends to.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 2250 (Why does 'cat items >> items' not compile, and how do I append a List to itself?)
Each of these is fine:
- //Read a copy: the stream reads 'copy' while '>>' appends to 'scores'.
- copy <- List() of Integer
- copy += scores
- cat copy >> scores
- //Or replace: '>' fills a fresh List and swaps it in when the stream is finished.
- cat scores | sort > scores
- //Or build the result in a new variable.
- sorted <- cat scores | sort | collect as List of Integer
How to fix it
- Read a copy: build a new collection of the same kind, append the original to it, and let 'cat' read the copy while '>>' appends to the original.
- Or replace the List with '>' - the result is built aside and swapped in when the stream is finished, so the stream can read what the List held.
- Or build the result in a new variable ('collect as List of ...') and keep the original as it was.
- If the report is on a 'tee', give the 'tee' a different List from the one 'cat' reads.
Common causes
- Writing the Unix idiom 'cat file >> file' to double or extend a List, a Set, a Dict, a PriorityQueue or a JSON
- Collecting the filtered elements back into the List they were filtered from, with '>>' instead of '>'
- A 'tee' that records what passes through into the very collection being read
See also
- E08276: another stream-source check, a for-range that can never move toward its end
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08277: the same variable is read by 'cat' and appended to ('>>' or 'tee') in one stream statement, so the read never reaches the end - input is output; read a copy instead, use '>' to replace it, or collect into a new variable
#!ek9 defines module error.e08277.bad defines function appendToItself() stdout <- Stdout() scores <- [3, 1, 2] //'>>' appends to 'scores' while 'cat' is still reading it, so the read can never reach the end. cat scores >> scores stdout.println($scores)
Fixed: Read a copy of the List, replace it with '>', or collect into a new variable
#!ek9 defines module error.e08277.good defines function appendWithoutReadingWhatIsAppendedTo() stdout <- Stdout() scores <- [3, 1, 2] //Read a copy: the stream reads 'copy' while '>>' appends to 'scores'. copy <- List() of Integer copy += scores cat copy >> scores //Or replace: '>' fills a fresh List and swaps it in when the stream is finished. cat scores | sort > scores //Or build the result in a new variable. sorted <- cat scores | sort | collect as List of Integer stdout.println($sorted)
Questions and answers
These Q&A entries show E08277 and its fix: