Why does EK9 reject manual close of local resources?

← Error Handling and Exceptions · Ref: Q802

EK9 raises E81055 when you manually close a locally-declared resource. Manual close is unsafe because if an exception occurs before the close statement, the resource leaks.

WHY UNSAFE

  resource <- MyResource("test")
  doWork()         //exception here?
  close resource   //might never execute!

Research shows ~32% of resource leak bugs are caused by exceptions occurring before manual close() calls.

CORRECT: TRY-WITH-RESOURCES

  try
    -> resource <- MyResource("test")
    doWork()
  //close() GUARANTEED to be called

WHAT IS ALLOWED

- Closing a PARAMETER (caller transferred ownership)
- Closing a FIELD (aggregate manages its own resources)
- try-with-resources for local resources

See Q137 for try-with-resources syntax. See Q803 for abandoned resource detection.

Example

defines module qa.errorhandling.manualclose

  defines class

    DatabaseConn
      connName <- String()

      DatabaseConn()
        -> connectionName as String
        connName: connectionName

      query()
        -> queryText as String
        <- queryResult as String: `${queryText} from ${connName}`

      operator close as pure
        require true

      override operator ? as pure
        <- rtn <- true

  defines function

    safeResourceUsage()
      stdout <- Stdout()

      try
        -> conn <- DatabaseConn("test-db")
        queryResult <- conn.query("SELECT 1")
        stdout.println(queryResult)

Common mistakes

E81055 — Manual close of a locally-declared resource is unsafe. If an exception occurs before the close statement, the resource leaks. Use try-with-resources instead. See ek9 -h E81055 for details.

Incorrect:

      conn <- DatabaseConn("test-db")
      queryResult <- conn.query("SELECT 1")
      stdout.println(queryResult)
      close conn

Correct:

      try
        -> conn <- DatabaseConn("test-db")
        queryResult <- conn.query("SELECT 1")
        stdout.println(queryResult)
Other ways to ask this
  • What triggers E81055 manual close of local resource?
  • Why must I use try-with-resources for local variables?
  • How do I properly close resources in EK9?

Coming from another language?

Java: allows manual close() but try-with-resources recommended since Java 7. Python: 'with' statement recommended but manual close allowed. Rust: RAII with Drop trait, automatic cleanup. Go: defer close() pattern, easy to forget. C#: using statement for IDisposable. EK9: compile-time error E81055, manual close of locals is impossible.

Keywords: close, leak, try, with, manual, E81055, local, resource, resources