E81069: a dynamic function has no 'operator close', so it can never close a NEW closeable it captures - capture one the enclosing scope owns (a try resource), or capture it in a dynamic class that closes it
What went wrong
A dynamic function captures a NEW closeable value - a constructor call such as '(res: Res("x"))', or a call that returns a new closeable. A capture of a new value is a transfer: the dynamic construct becomes its only owner. A dynamic function has no 'operator close', so nothing could ever close what it owns, and the resource would leak.
A capture that is not new - a named variable '(res)', a try resource, a property - is a borrow: the scope that made the dynamic function still owns it and closes it, so it is not this error.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1880 (How do I release the resources my class holds - and what does 'default operator close' close for me?)
- ek9 -q 1520 (When does EK9 close a closeable value, and where may I keep one?)
How to fix it
Acquire the resource where it is used and capture it by name, so the enclosing try owns it and the dynamic function only borrows it (good.ek9 in the [EXAMPLE] section below). Or capture the new value in a dynamic CLASS, which can own it - it declares its own generated close, which closes the capture, and is itself the try's resource:
try -> reader <- (res: Res("journal")) with trait of Readable as class override text() <- rtn as String: res.read() default operator close default operator ? rtn: reader.text()
Common causes
- Creating the resource inline in the capture list for brevity.
- Porting a Java lambda that closed over a stream it opened itself.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81069: a dynamic function has no 'operator close', so it can never close a NEW closeable it captures - capture one the enclosing scope owns (a try resource), or capture it in a dynamic class that closes it
#!ek9 defines module error.e81069.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 Reader() as abstract <- text as String? makeReader() <- rtn as Boolean? reader <- (res: Res("journal")) is Reader as function text: res.read() rtn: reader?
Fixed: Acquire it in a try and capture it by name - a borrow; the try closes it
#!ek9 defines module error.e81069.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 Reader() as abstract <- text as String? readJournal() <- rtn as String? try -> res <- Res("journal") reader <- (res) is Reader as function text: res.read() rtn: reader()
Fixed: Or capture the new value in a dynamic CLASS, whose generated close closes it
#!ek9 defines module error.e81069.good.class defines class Res name as String? default private Res() Res() -> label as String name: label read() as pure <- rtn as String: `read ${name}` operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) default operator ? defines trait Readable text() as abstract <- rtn as String? defines function readJournal() <- rtn as String? try -> reader <- (res: Res("journal")) with trait of Readable as class override text() <- rtn as String: res.read() default operator close default operator ? rtn: reader.text()
Questions and answers
These Q&A entries show E81069 and its fix: