Can I call close() on a resource like a method?
← Error Handling and Exceptions · Ref: Q1660
No. The close operator is never called as a method - 'res.close()', 'this.close()', a bare 'close()' inside the type, 'make().close()' and 'super.close()' are all E81060, on any receiver. A closeable value is closed by its OWNER, exactly once:
- a try-with-resources resource is closed by its try, when the try ends;
- a closeable value that is never named is closed by the statement that made it;
- a property is closed by its type's GENERATED close - 'default operator close', or after the body of an 'operator close' you write - which closes the type's own closeable properties and then calls its super class's close:
default operator close
The method form would get round that rule: a try resource closed inside its try is closed again when the try ends, a parameter or capture is closed while its owner still uses it, and a property closed in an ordinary method is closed again by its type's operator close.
To stop early, end the work with a condition (a loop flag) instead of closing the value under its owner. 'super.close()' is no exception: the generated close already calls the super class's close, so calling it by hand would close the super's part twice.
In the program below, the try closes the reader once, the loop stops on a flag, and Journal's generated close closes its own property and then calls its super's.
Example
defines module qa.errorhandling.closeisnotamethod defines class Reader as open name as String? default private Reader() Reader() -> label as String name: label read() as pure <- rtn as String: `read ${name}` operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) default operator ? Journal is Reader held as Reader? Journal() -> label as String super(label) held: Reader(label + "-held") default operator close default operator ? defines program CloseIsNotAMethod() stdout <- Stdout() try -> reader <- Reader("first") reading <- true while reading stdout.println(reader.read()) reading: false try -> journal <- Journal("journal") require journal?
Common mistakes
E81060 — The try owns the reader and closes it when the try ends, so calling close() here would close it twice. End the loop with a condition instead. See ek9 -h E81060 for details.
Incorrect:
stdout.println(reader.read())
reader.close()
Correct:
stdout.println(reader.read())
reading: false
Other ways to ask this
- Why is conn.close() an error E81060?
- How do I close a file or connection early in EK9?
- Can a handler call close() on a server it captured?
- How does a sub type close the resources its super holds?
Coming from another language?
Java: close() is an ordinary method - any code holding the reference may call it, any number of times, and keep using the object afterwards; try-with-resources then closes it again. Python: f.close() inside a 'with' block, followed by the block's own close. EK9: one way to close, used only by the owner - the try, the statement, or the type's generated close (E81060 for the method form, super.close() included).
Keywords: try-with-resources, super.close, close, close(), double close, use after close, E81060, operator close