E81067: if you hold it, you close it - a type with a closeable property must declare its own 'operator close' ('default operator close' or one you write); an inherited close cannot see this type's property
What went wrong
If you hold it, you close it. A class, record, component or dynamic class has a closeable property (its type has an 'operator close') but declares no 'operator close' of its own. Nothing would ever close that property.
The type must DECLARE its own close - 'default operator close', or one you write. An inherited close does not count: it was written for the super-type and cannot see a property a sub-type adds, so a sub-type that relies on it leaks its own property. An abstract close does not count either, and a 'by'-delegation proxy close closes only its delegate.
A dynamic class that captures a NEW closeable ('(res: Res("x"))') owns it and holds it the same way. Not counted as held: an injected property ('store as Store!' - the application owns it), the delegate of a 'by' proxy close, a property typed as a bare type parameter T, and a capture of a value that is not new (a named variable or '(owner: this)' - a borrow).
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1860 (Which of my types must declare their own operator close, and what may that close do?)
- 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?)
- ek9 -q 1780 (Can I put a closeable resource in a List, an Optional or my own generic type?)
- ek9 -q 1900 (How can my code use a closeable resource it does not own?)
How to fix it
Declare the close in the type that holds the property. Its generated close closes the property and then calls the super class's close (the [EXAMPLE] section below: a Journal that adds 'notes' to a Ledger declares its own 'default operator close').
Write an 'operator close' instead only for extra work; it runs first, with everything still open, and the generated close follows it.
If the value is not this type's to close, do not hold it as a property: take it as a parameter where it is used (a loan), or acquire it in a try.
Common causes
- A sub-type adds a connection or file to a super-type that already has a close, and relies on the inherited one.
- A holder that keeps a resource it was given, expecting someone else to close it.
- A record or component that makes a resource in a property initialiser.
- A 'by'-delegated type that also holds a second closeable property.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81067: if you hold it, you close it - a type with a closeable property must declare its own 'operator close' ('default operator close' or one you write); an inherited close cannot see this type's property
#!ek9 defines module error.e81067.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}`) Ledger as open book as Res? default private Ledger() Ledger() -> title as String book: Res(title) default operator ? default operator close Journal is Ledger notes as Res? Journal() -> title as String super(title) notes: Res(`${title} notes`) default operator ?
Fixed: Declare its own close - the generated close closes notes, then calls Ledger's
#!ek9 defines module error.e81067.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}`) Ledger as open book as Res? default private Ledger() Ledger() -> title as String book: Res(title) default operator ? default operator close Journal is Ledger notes as Res? Journal() -> title as String super(title) notes: Res(`${title} notes`) default operator ? default operator close
Questions and answers
These Q&A entries show E81067 and its fix: