Can a type that holds a closeable resource use 'default operator :=:'?
← Error Handling and Exceptions · Ref: Q1843
No. The generated copy is shallow: it copies each property by reference. On a type that holds a closeable property, after 'first :=: second' both objects would hold second's resource, both would close it, and the resource first held would never be closed. No generated copy can be right for a resource, so 'default operator :=:' - written alone, or by the bare 'default operator', which includes it - is error E81065 on such a type.
Ask only for the default operators the type needs ('default operator ?', 'default operator $', ...). If the type really must be copied, write 'operator :=:' yourself and copy only the values that are not resources: each object keeps, and later closes, the resource it acquired itself.
The program below copies one holder over another with a hand-written copy: the first takes the second's label but keeps its own resource, and each resource is closed exactly once.
Example
defines module qa.errorhandling.nodefaultcopyofaresourceholder defines class Resource name as String? default private Resource() Resource() -> text as String name: text label() as pure <- rtn as String: name operator close as pure stdout <- Stdout() stdout.println(`closed ${name}`) default operator ? Holder label as String? held as Resource? default private Holder() Holder() -> text as String label: String(text) held: Resource(`${text}-resource`) describe() as pure <- rtn as String: `${label} holding ${held.label()}` <?- Copies only what is not a resource: each holder keeps the resource it acquired -?> operator :=: -> other as Holder label :=: other.label default operator close default operator ? defines program CopyAResourceHolder() stdout <- Stdout() try -> first <- Holder("first") second <- Holder("second") first :=: second stdout.println(second.describe()) stdout.println(first.describe())
Common mistakes
E81065 — The generated copy would copy the closeable property by reference, so both holders would close one resource. Write ':=:' and copy only what is not a resource. See ek9 -h E81065 for details.
Incorrect:
default operator :=:
Correct:
operator :=: -> other as Holder label :=: other.label
Other ways to ask this
- Why is 'default operator' an error on my class that holds a connection?
- How do I copy an object that owns a resource?
- Why can't the generated copy operator copy a closeable property?
- What does E81065 mean?
Coming from another language?
Java: clone() of an object with a Socket field shares the socket, and closing both clones closes it twice. C++: the implicitly generated copy constructor copies a raw handle the same way, which is why the rule of three/five exists. Rust: a type holding a File is not Copy and Clone must be written. EK9: the generated copy is refused on a type that holds a closeable (E81065); write ':=:' and copy only what is not a resource.
Keywords: copy, close, default operator, shallow copy, operator close, E81065, closeable, :=:, property