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
#!ek9 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: :=:, E81065, close, closeable, copy, default operator, operator close, property, shallow copy