What happens when a closeable resource is never closed?
← Error Handling and Exceptions · Ref: Q803
EK9 raises E81056 when a variable with a close() operator is created but never closed and does not escape the current scope. This is a guaranteed resource leak.
WHAT COUNTS AS ESCAPE
A resource escapes (ownership transferred) when:
- RETURNED: assigned to return variable
- STORED: assigned to a field or collection
- PASSED: given to another method as argument
- WRAPPED: placed in Optional, Result, or container
FIX OPTIONS
1. try-with-resources: automatic close when scope ends (recommended)
2. Return it: transfer ownership to the caller
3. Pass it: give to another component for management
4. Store it: place in a container for batch management
Research shows ~30% of resource leak bugs are caused by developers forgetting to close resources entirely.
See Q802 for manual close rejection. See Q137 for try-with-resources syntax.
Example
defines module qa.errorhandling.resourceneverclosed defines class FileConn fileName <- String() FileConn() -> name as String fileName: name readAll() <- content as String: "contents of " + fileName operator close as pure require true override operator ? as pure <- rtn <- true defines function safeFileRead() stdout <- Stdout() try -> fileConn <- FileConn("log.txt") content <- fileConn.readAll() stdout.println(content)
Common mistakes
E81056 — A closeable resource was created but never closed via try-with-resources and does not escape the scope. This is a guaranteed resource leak. Wrap it in try-with-resources. See ek9 -h E81056 for details.
Incorrect:
fileConn <- FileConn("log.txt") content <- fileConn.readAll() stdout.println(content)
Correct:
try -> fileConn <- FileConn("log.txt") content <- fileConn.readAll() stdout.println(content)
Other ways to ask this
- What triggers E81056 resource never closed or escaped?
- How does EK9 detect abandoned resources?
- Why must closeable resources be closed or transferred?
Coming from another language?
Java: unclosed resources only detected by FindBugs/SpotBugs, not the compiler. Python: no detection, relies on linters. Rust: Drop trait guarantees cleanup. Go: no detection (defer is voluntary). C#: Roslyn CA2000 warns but code still compiles. EK9: compile-time error E81056, abandoned resources cannot exist.
Keywords: close, leak, try, transfer, E81056, escape, ownership, abandoned, resource