E81062: a closeable value enters a property or a try resource only when it is NEW (a constructor call, or a call that returns a new closeable) - anything else already has an owner that closes it
What went wrong
A closeable value (its type has an 'operator close') enters a slot that will close it - a property of a closeable type, or a try-with-resources resource - but it is not a NEW value. Something else already owns it, and that owner closes it too: the resource would be closed twice, and used after it was closed.
A closeable has exactly ONE owner. A value is new when it is a constructor call (Res("x")) or a call whose declared return type is closeable and which does not hand back part of its receiver or an argument (TextFile(p).input(), a function that returns a Res it made). Anything else has an owner already:
- a try resource, or a parameter (the caller owns it);
- another object's property (rec.held, other.held) or your own (held);
- a value given to a constructor that keeps it in a closeable property, when the value is a named try resource or any other name - Holder(res) with res a try resource gives res two owners, the try and the holder.
A constructor that stores its own parameter in a closeable property (held: res) takes ownership of it - a transfer - so every construction must hand that parameter a new value, and the parameter may go into only one property.
Who owns a closeable
Every closeable value has exactly one owner, decided by where it lives, and only the owner's generated code closes it:
- a LOCAL is a try-with-resources resource: the try closes it when it ends.
- a value that is never NAMED is owned by the statement that made it - a call result or a constructed value - and closed when that statement finishes.
- a PROPERTY is owned by its object: the type's close (the generated one, or the chain after one you write) closes it.
- a PARAMETER belongs to the caller, which lends it for the call.
- a CAPTURE of a named value belongs to the scope that made the dynamic function or class; a NEW captured value is owned by the dynamic class.
- the RETURNING variable is handed to the caller, who becomes the owner.
- 'this' is owned by whoever made the object.
Nothing else may close it: there is no 'close' statement (E01094) and the close operator is never called as a method (E81060). That is why a slot that will close its value may only take a NEW one.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1840 (Can I give my object a resource I have already opened?)
- ek9 -q 1520 (When does EK9 close a closeable value, and where may I keep one?)
- ek9 -q 1740 (How do I let other code use a resource my object owns without letting it close or keep it?)
- ek9 -q 1900 (How can my code use a closeable resource it does not own?)
How to fix it
Hand the slot a NEW value, made where it is stored: the try resource is 'Holder(Res("shared"))', not a Holder of a Res the try already names (the [EXAMPLE] section below).
Use a resource someone else owns through a PARAMETER instead of taking it: a function given 'res' uses it directly, never as a resource of a try of its own.
To let other code use a resource your object holds, lend it - pass it to a function or method as a parameter (the loan pattern) - never put it in a second try or a second object.
Common causes
- 'try -> x <- param' or 'try -> x <- rec.held' to "make sure it is closed": its owner already closes it.
- Constructing a wrapper around a named try resource: Holder(res).
- A hand-written ':=:' or ':^:' that copies another object's closeable property into its own.
- One constructor parameter stored into two properties.
See also
- E81062: Closeable slot given a value that is not new (this error)
- E81063: Closeable slot re-pointed (a property, returning variable or try resource)
- E81065: 'default operator :=:' on a type that holds a closeable
- E81056: Closeable held in a named local (must be a try resource)
- E81057: Closeable return is not a new instance
- E01094: 'close' is not a statement (closing is generated)
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81062: a closeable value enters a property or a try resource only when it is NEW (a constructor call, or a call that returns a new closeable) - anything else already has an owner that closes it
#!ek9 defines module error.e81062.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}`) Holder held as Res? default private Holder() Holder() -> res as Res held: res default operator ? default operator close defines function share() <- rtn as Boolean? try -> res <- Res("shared") holder <- Holder(res) rtn: holder?
Fixed: Hand the slot a new value - the holder is its only owner
#!ek9 defines module error.e81062.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}`) Holder held as Res? default private Holder() Holder() -> res as Res held: res default operator ? default operator close defines function share() <- rtn as Boolean? try -> holder <- Holder(Res("shared")) rtn: holder?
Questions and answers
These Q&A entries show E81062 and its fix: