Why does 'cat items >> items' not compile, and how do I append a List to itself?
← Streams and Pipelines · Ref: Q2250
A stream pulls from its source one element at a time. '>>' appends to its target as each element arrives, so 'cat items >> items' (or a 'tee' into 'items' under 'cat items') adds to the List while it is still being read, and the read never reaches the end. GNU cat refuses the same thing on a file: "input file is output file". The compiler reports it as E08277, on the target, whenever the same variable - by identity, not by name - is a 'cat' source and an appending target ('>>' or 'tee') of one statement; 'cat a, items >> items' and 'this.items' against plain 'items' are the same variable too.
Read a COPY ('copy += items' on a new List, then 'cat copy >> items'), or REPLACE with '>', which fills a fresh List and swaps it in when the stream is finished ('cat items | sort > items' is fine), or collect into a new variable. The rule has no list of types: a Set, a Dict, a PriorityQueue or a JSON that is read and appended to is E08277 too, so read a copy of those as well. A variable held by another object ('other.items') is another variable.
Where the compiler cannot see two names for one List (or JSON) - 'alias <- items' then 'cat items >> alias', or one List passed 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", for a List, a Set, a Dict, a PriorityQueue or a JSON alike (it was "No such element" for a List, and nothing at all for a Set or a Dict): the statement compares the objects it reads with the objects it appends to. A List is never silently copied for you: the error is the answer. The same holds for a 'for' loop that adds to the List it is looping over.
Example
#!ek9 defines module qa.streams.append.list.to.itself defines function appendAll() -> source as List of Integer target as List of Integer cat source >> target defines program AppendListToItself() stdout <- Stdout() //Read a copy while '>>' appends to the original. items <- [1, 2, 3] copy <- List() of Integer copy += items cat copy >> items stdout.println(`appended ${items} from ${copy}`) //'>' fills a fresh List and swaps it in when the stream is finished, so reading what it held is fine. sorted <- [3, 1, 2] cat sorted | sort > sorted stdout.println(`replaced ${sorted}`) //Or build the result in a new variable. original <- [1, 2, 3] doubled <- cat original, original | collect as List of Integer stdout.println(`collected ${doubled}`) //E08277 is for every type: a Set read and appended to is rejected too, so read a copy of it. unique <- Set() of Integer unique += 1 unique += 2 snapshot <- Set() of Integer snapshot += unique cat snapshot >> unique stdout.println(`Set ${unique}`) //The compiler cannot see that source and target are one List here, so the List reports it as it is read. same <- [1, 2] try appendAll(same, same) stdout.println(`appended ${same}`) catch -> ex as Exception stdout.println(`alias: ${ex.reason()}`)
Common mistakes
E08277 — The stream reads 'items' while '>>' appends to it, so the read never ends. Read a copy of the List, use '>' to replace it, or collect into a new variable.
Incorrect:
cat items >> items
Correct:
cat copy >> items
Other ways to ask this
- How do I double a list with a stream, like cat file >> file?
- Why does cat scores >> scores fail with input is output?
- Can I append a list to itself with a stream pipeline?
- I get No such element when a stream appends to the list it is reading, what is wrong?
- How do I tee a stream back into the list it reads from?
Coming from another language?
Unix shell: 'cat file >> file' fails with 'input file is output file'. Java: adding to an ArrayList inside a for-each or stream over it throws ConcurrentModificationException. Python: 'for x in items: items.append(x)' never ends. EK9: E08277 at compile time where the compiler can see it, an Exception 'List changed while it was being read' where it cannot.
Keywords: >>, No such element, append, cat, changed while read, copy, input is output, same list, tee