E01094: 'close' is not a statement in EK9 - closing is generated: declare 'default operator close' (or write 'operator close' for extra work); a local closes through try or its statement
What went wrong
'close' is not a statement in EK9. Every close is generated by the compiler, so a close written by hand could only close a value a second time, or close it while its owner is still using it:
- a try-with-resources resource is closed when its try ends;
- a closeable value a statement makes but never names is closed when that statement finishes;
- a type's own closeable properties are closed by its close operator (the generated one, or one you write for extra work), which closes them after its body, last acquired first, then calls its super class's close.
The grammar keeps 'close x' only to give this error, as it keeps 'break' and 'return'.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1600 (Who closes a closeable value, and can I close one myself?)
- ek9 -q 1880 (How do I release the resources my class holds - and what does 'default operator close' close for me?)
- ek9 -q 802 (Why does EK9 reject manual close of local resources?)
- ek9 -q 1902 (What happens when a close throws an exception - are the other resources still closed?)
Rationale
A manual close() call is skipped whenever an exception is thrown before it is reached, and the opposite mistake is just as common: a value closed by code that does not own it - a double close, or a use after close. C++ and Swift never close a member by hand: the destructor runs, then the members and the base are released automatically. EK9 applies that rule to every close.
How to fix it
Who owns the value decides what replaces the 'close'.
A local: declare it as a try-with-resources resource ('try' with '-> conn <- ...'), and the try closes it when it ends (good_local.ek9 in the [EXAMPLE] section below). Or, when one statement is all you need, do not name it at all - 'use(Connection(a))'
- and the statement closes it.
Your own property: delete the 'close'. A close that only closed properties becomes 'default operator close'; keep a written 'operator close' only for extra work, which runs first with every property still open. The [EXAMPLE] section below shows 'close conn' in a Holder's close, and the Holder with 'default operator close' instead (good.ek9).
A parameter, a capture, the returning variable or a call result: delete the 'close' - its owner (the caller's try, the scope that made the dynamic construct, the caller, the statement) closes it.
To stop work early (a loop, a server), end it with a condition or call the server's stop() - never close the value under its owner.
Common causes
- Java, C# or Python habit: closing at the end of a block.
- Code written before closing was generated, closing each property in its type's own close.
- A 'release', 'disconnect' or 'reset' method that closes a held resource. Make a new owning object (or acquire afresh in a new try) instead.
- A handler closing a captured server or connection to stop a loop.
See also
- E01094: 'close' is not a statement (this error)
- E81060: Close operator called as a method (never, 'super.close()' included)
- E81056: Closeable held in a named local (must be a try-with-resources resource)
- E81062: Closeable slot given a value that is not new (who owns what)
- E81067: A type that holds a closeable must declare its own operator close
- E01070: 'break' not supported
- E01072: 'return' not supported
https://ek9.io/flowControl.html#try_catch https://ek9.io/forAI.json#$.excludedFeatures.features[?(@.keyword=="close")]
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E01094: 'close' is not a statement in EK9 - closing is generated: declare 'default operator close' (or write 'operator close' for extra work); a local closes through try or its statement
#!ek9 defines module error.e01094.bad defines class Connection address as String? default private Connection() Connection() -> address as String this.address: address default operator ? operator close as pure stdout <- Stdout() stdout.println("closed " + address) Holder conn as Connection? default private Holder() Holder() -> address as String conn: Connection(address) default operator ? operator close as pure close conn
Fixed: Let the generated close do it: default operator close closes conn
#!ek9 defines module error.e01094.good defines class Connection address as String? default private Connection() Connection() -> address as String this.address: address default operator ? operator close as pure stdout <- Stdout() stdout.println("closed " + address) Holder conn as Connection? default private Holder() Holder() -> address as String conn: Connection(address) default operator ? default operator close
Fixed: A local closes through its try: declare it as the try's resource
#!ek9 defines module error.e01094.good.local defines function readFirst() -> path as FileSystemPath stdout <- Stdout() try -> input <- TextFile(path).input() stdout.println(input.next())
Questions and answers
These Q&A entries show E01094 and its fix: