E81056: a closeable value held in a named local must be a try-with-resources resource

Category: E81xxx-E83xxx Test configuration, execution and coverage · Reported in phase: PRE_IR_CHECKS · Classification: CLOSEABLE_LOCAL_NOT_A_TRY_RESOURCE · All error codes

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

  • E81056: Closeable held in a named local (this error)
  • E81059: Closeable stored where the declared type cannot close it
  • E81062: Closeable slot given a value that is not new (who owns what)
  • E01094: 'close' is not a statement (closing is generated)

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: