E81074: an Exception is a value carried to a handler, not a resource - it has no 'operator close', declared, defaulted or inherited; put the resource in a type of its own and close it there
What went wrong
An Exception, or a sub-type of one, has an 'operator close' - one it writes, one it asks for with 'default operator close' (it holds a closeable property), or one it must implement because it takes a trait that carries a close. An exception is a value carried to a handler, not a resource, so it may not be closeable.
A thrown exception has no try that owns it, and a 'catch' is not an owner: the exception is made, thrown, caught and dropped, and its close was never called. Making every handler an owner would close a value that a handler may keep, log or rethrow. So the rule is the simpler one - an exception carries values (a reason, a code, the name of what failed) and never holds a resource. A resource that the failure concerns belongs to a type of its own, which closes it in its 'operator close'.
The error is reported once down a hierarchy, on the first type that is closeable; a sub-type of that exception is not reported again.
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?)
How to fix it
Remove the 'operator close' from the exception. Where it closed a resource, hold the resource in a class of your own that owns it (closed by its own 'operator close'), acquire it in a 'try' where it is used, and let the exception carry only a String or a number describing what happened (good.ek9 in the [EXAMPLE] section below).
Common causes
- Giving an exception a handle - a connection, a file - so the handler can inspect it, and then closing it in the exception.
- Writing 'default operator close' on an exception with a closeable property.
- Taking a 'with trait of' a trait that has an 'operator close' on an exception.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81074: an Exception is a value carried to a handler, not a resource - it has no 'operator close', declared, defaulted or inherited; put the resource in a type of its own and close it there
#!ek9 defines module error.e81074.bad defines class Failure extends Exception Failure() -> reason as String super(reason) default operator ? operator close as pure stdout <- Stdout() stdout.println("failure closed") defines function failedWork() <- rtn as String: "none" try throw Failure("boom") catch -> ex as Exception rtn: `caught ${ex}`
Fixed: Remove the operator close - an exception is a value, not a resource
#!ek9 defines module error.e81074.good.fix defines class Failure extends Exception Failure() -> reason as String super(reason) default operator ? defines function failedWork() <- rtn as String: "none" try throw Failure("boom") catch -> ex as Exception rtn: `caught ${ex}`
Fixed: Hold the resource in a type of your own that closes it, and let the exception carry plain text
#!ek9 defines module error.e81074.good defines class Failure extends Exception Failure() -> reason as String super(reason) default operator ? Connection name as String? default private Connection() Connection() -> label as String name: label send() as pure -> text as String <- rtn as String: `${name} sent ${text}` default operator ? operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) defines function failedWork() <- rtn as String: "none" try throw Failure("boom") catch -> ex as Exception rtn: `caught ${ex}` describeConnection() <- rtn as String: String() try -> connection <- Connection("link") rtn: connection.send("hello")