E81056: a closeable value held in a named local must be a try-with-resources resource
What went wrong
A local variable holds a closeable value (its type has an 'operator close') but it is not a try-with-resources resource. Nothing would ever close it.
EK9 decides who closes a closeable value from where it lives:
- NEVER NAMED: owned by the statement that created it, and closed when that statement finishes - normally, when a stream stage stops early, or when an exception leaves the statement.
- NAMED: must be declared as a try-with-resources resource, and is closed when the try ends.
A named closeable anywhere else is this error.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1520 (When does EK9 close a closeable value, and where may I keep one?)
- ek9 -q 803 (What happens when a closeable resource is never closed?)
How to fix it
Declare it as a try-with-resources resource (good.ek9 in the [EXAMPLE] section below reads a file's first line inside 'try' with '-> input <- ...'). Or, when one statement is all you need, do not name it - the statement closes it (good_unnamed.ek9 streams the file straight into a List).
What is not a local
- The RETURNING variable: returning a closeable hands it to the caller (a factory, good_factory.ek9), who names it in a try or leaves it unnamed.
- A PROPERTY: the object owns it, and its type's close (the generated close, or the generated chain after a close you write) closes it.
- A PARAMETER: the caller owns it.
Common causes
- Opening a file, connection or server into a variable and using it over several statements without a try.
- Passing a named closeable on to a function or constructor: that does not transfer it - the local still holds it. Name it in the try and pass it from there.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81056: a closeable value held in a named local must be a try-with-resources resource
#!ek9 defines module error.e81056.bad defines function firstLine() -> path as FileSystemPath <- rtn as String: String() input <- TextFile(path).input() if input.hasNext() rtn: input.next()
Fixed: Name it as a try-with-resources resource - the try closes it
#!ek9 defines module error.e81056.good defines function firstLine() -> path as FileSystemPath <- rtn as String: String() try -> input <- TextFile(path).input() if input.hasNext() rtn: input.next()
Fixed: Or return it: ownership passes to the caller
#!ek9 defines module error.e81056.good.factory defines function openData() -> path as FileSystemPath <- rtn as CloseableStringInput: TextFile(path).input()
Fixed: Or leave it unnamed - the statement that made it closes it
#!ek9 defines module error.e81056.good.unnamed defines function allLines() -> path as FileSystemPath <- rtn as List of String: List() cat TextFile(path).input() > rtn
Questions and answers
These Q&A entries show E81056 and its fix: