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

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

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

  • E81060: Close operator called as a method (this error)
  • E01094: 'close' is not a statement (closing is generated)
  • 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)

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: