Can I give my object a resource I have already opened?
← Error Handling and Exceptions · Ref: Q1840
Not if something else already owns it. Every closeable value has exactly ONE owner, and that owner closes it. A closeable property (closed by its type's operator close) and a try-with-resources resource (closed when the try ends) are slots that will close what they hold, so a closeable may enter one only when it is NEW - a constructor call such as Journal("audit"), or a call whose declaration returns a new closeable, such as TextFile(path).input() or a function that returns a Journal it made. Anything else is error E81062: a parameter (the caller owns it), a try resource, your own property or another object's property already has an owner, and storing it again would close it twice - and close it while its first owner is still using it.
A constructor that stores its own parameter in a closeable property takes ownership of it - a transfer - so every construction must hand that parameter a new value. Logger(Journal("audit")) is right: the logger is the journal's only owner. Logger(journal), with journal a try resource, gives one journal two owners, the try and the logger, and is E81062 at the argument. The same holds when a constructor forwards its parameter to super(...), and a parameter may go into only one property.
Code that only USES a resource someone else owns takes it as a parameter and leaves the closing to its owner - the loan pattern. The program below gives the logger a new journal and lends a second journal to a function; every close prints, so you can see each journal closed exactly once.
Example
defines module qa.errorhandling.closeableslotneedsanewvalue defines class Journal name as String? default private Journal() Journal() -> label as String name: label write() -> text as String stdout <- Stdout() stdout.println(`${name}: ${text}`) operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) default operator ? <?- Keeps the journal it is given: a transfer, so it must be handed a NEW journal -?> Logger journal as Journal? default private Logger() Logger() -> target as Journal journal: target log() -> text as String journal.write(text) default operator close default operator ? defines function <?- Only uses a journal someone else owns: a parameter is a loan -?> note() -> journal as Journal journal.write("borrowed") defines program FreshStoreDemo() try -> logger <- Logger(Journal("audit")) logger.log("started") try -> journal <- Journal("notes") note(journal)
Common mistakes
E81062 — Logger keeps the journal it is given in a closeable property, so it must be handed a NEW one. A named try resource already has an owner, the try, and both would close it. See ek9 -h E81062 for details.
Incorrect:
-> audit <- Journal("audit") logger <- Logger(audit)
Correct:
-> logger <- Logger(Journal("audit"))
Other ways to ask this
- Why is 'logger <- Logger(journal)' an error when journal is a try resource?
- Why can't I write 'try -> mine <- param' to make sure a parameter is closed?
- Can a try resource be another object's property?
- What does E81062 mean?
Coming from another language?
Java: 'new BufferedWriter(writer)' takes the writer, and closing both the wrapper and the original in two try-with-resources blocks closes it twice; nothing stops you. C#: 'leaveOpen' flags and CA2000/CA2213 analyzers try to track who disposes what. Rust: moving a value into a struct transfers ownership, and using the moved value again is a compile error. EK9: a closeable may enter a property or a try resource only when it is new (E81062), so every closeable has one owner by construction.
Keywords: loan, close, constructor, transfer, operator close, try-with-resources, E81062, ownership, fresh, new value, closeable, property