E81064: closeable properties are closed in reverse declaration order, so a constructor must acquire them in declaration order
What went wrong
A constructor sets a closeable property while a closeable property declared AFTER it already holds a resource: the constructor acquires them in a different order from the one they are declared in.
An object's closeable properties are released in REVERSE declaration order, which is reverse acquisition order - last made, first closed - only when they are acquired in declaration order. That matters as soon as one resource depends on another: a buffered writer over a file must be closed (and flushed) BEFORE the file. Acquired out of order, the file would be closed first and the writer's last flush would be lost.
Property initialisers already run in declaration order, before the constructor body, so a property with an initialiser counts as acquired before anything the body sets.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1842 (In what order are the resources my object holds closed?)
How to fix it
Declare the properties in the order the constructor acquires them - the foundation first, what depends on it after - or acquire them in the constructor in the order they are declared. The [EXAMPLE] section below shows a constructor setting 'dependent' before 'foundation' when they are declared the other way round, then the two in the same order.
Common causes
- Adding a new resource property at the top of the type while the constructor acquires it last.
- Mixing an initialised closeable property, declared after another, with a constructor that sets the earlier one.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E81064: closeable properties are closed in reverse declaration order, so a constructor must acquire them in declaration order
#!ek9 defines module error.e81064.bad defines class Res name as String? default private Res() Res() -> label as String name: label default operator ? operator close as pure require name? <?- BAD: 'dependent' is declared first but acquired second -?> BodyOrder dependent as Res? foundation as Res? BodyOrder() foundation: Res("foundation") dependent: Res("dependent") default operator ? default operator close <?- BAD: 'late' is initialised before the constructor body sets 'early', which is declared before it -?> InitialiserFirst early as Res? late as Res: Res("late") InitialiserFirst() early: Res("early") default operator ? default operator close <?- BAD: out of order on one path is enough -?> OnOnePath first as Res? second as Res? default private OnOnePath() OnOnePath() -> secondFirst as Boolean if secondFirst second: Res("second") first: Res("first") else first: Res("first") second: Res("second") default operator ? default operator close
Fixed: Declare the closeable properties in the order they are acquired
#!ek9 defines module error.e81064.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}`) BodyOrder foundation as Res? dependent as Res? BodyOrder() foundation: Res("foundation") dependent: Res("dependent") default operator ? default operator close
Questions and answers
These Q&A entries show E81064 and its fix: