E81060: the close operator is never called as a method, 'super.close()' included - make the value a try-with-resources resource; a type's own properties and its super class are closed by its generated close
What went wrong
A type's close operator is called as a METHOD: 'res.close()', 'this.close()', a bare 'close()' inside the type, 'make().close()' or 'super.close()' - inside an 'operator close' included. EK9 code never closes anything: there is no 'close' statement (E01094) and no call form. Closing is done for you, in three generated places, and calling the operator yourself closes a value a second time or while its owner is still using it:
- a try-with-resources resource is closed when its try ends.
- a value a statement makes and never names is closed when that statement finishes.
- a type's close - 'default operator close' or one you write - closes the type's own closeable properties after its body and then calls its super class's close, so 'super.close()' inside it would close the super's part twice.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1660 (Can I call close() on a resource like a method?)
- ek9 -q 1880 (How do I release the resources my class holds - and what does 'default operator close' close for me?)
How to fix it
A local or a try resource: declare it as a try-with-resources resource and delete the call - the try closes it (the [EXAMPLE] section below).
A parameter or a capture: delete the call - its owner closes it.
Your own property, inside 'operator close' or anywhere else: delete the call - the generated chain closes it after the close body. A close that only closed properties becomes 'default operator close'.
A sub type's close: delete 'super.close()' - the generated chain calls it after the close body (good_subtype.ek9 below prints "closing", then Res's close runs). When the body did nothing else, the close becomes 'default operator close'.
To stop work early (a loop, a server), end it with a condition rather than closing the value under its owner.
Common causes
- Java or Python habit: 'conn.close()' at the end of a block.
- A sub type chaining to its super's close by hand.
- A handler or callback closing a captured resource to stop a loop.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81060: the close operator is never called as a method, 'super.close()' included - make the value a try-with-resources resource; a type's own properties and its super class are closed by its generated close
#!ek9 defines module error.e81060.bad defines class Res name as String? default private Res() Res() -> label as String name: label read() as pure <- rtn as String: `read ${name}` default operator ? operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) defines function readOnce() <- rtn as String? try -> res <- Res("journal") rtn: res.read() res.close()
Fixed: Let the owner close it - the try does, exactly once
#!ek9 defines module error.e81060.good defines class Res name as String? default private Res() Res() -> label as String name: label read() as pure <- rtn as String: `read ${name}` default operator ? operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) defines function readOnce() <- rtn as String? try -> res <- Res("journal") rtn: res.read()
Fixed: A sub type's close never calls 'super.close()': the generated chain calls it
#!ek9 defines module error.e81060.good.subtype defines class Res as open name as String? default private Res() Res() -> label as String name: label operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) default operator ? LoggedRes extends Res LoggedRes() -> label as String super(label) //Its own work only: Res's close runs after it, generated override operator close as pure stdout <- Stdout() stdout.println("closing") defines function readOnce() try -> res <- LoggedRes("journal") require res?
Questions and answers
These Q&A entries show E81060 and its fix: