Skip to content

Commit e03edf1

Browse files
committed
Add auto close proposal
1 parent 97287eb commit e03edf1

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

proposals/0000-auto-closing.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Auto Closing
2+
3+
* Proposal: [HXP-NNNN](NNNN-auto-closing.md)
4+
* Author: [Aidan Lee](https://github.com/Aidan63)
5+
6+
## Introduction
7+
8+
Many classes contain a `close` function responsible for cleaning up handles, native resources, or other things which are outside of the control of the GC or which may not want to be kept around until the GC runs. This proposal introduces a new `autoclose` keyword to variable declarations which ensures the `close` function is automatically called when execution of the current block ends.
9+
10+
## Motivation
11+
12+
Leaking resources from these classes is very easy as the user has to manually call `close` and needs to take precautions against exceptions which could prevent the function being executed. Haxe also lacks a `finally` for exceptions which has been the traditional recommendation in other languages which means users have to write excessively verbose try catches to deal with any exceptions and not leak resources.
13+
14+
```haxe
15+
function bar() {
16+
final reader = File.read("input.txt", false);
17+
try
18+
{
19+
final writer = File.write("output.txt", false);
20+
21+
try
22+
{
23+
while (!reader.eof()) {
24+
writer.writeString(reader.readLine());
25+
}
26+
}
27+
catch (exn)
28+
{
29+
writer.close();
30+
31+
throw exn;
32+
}
33+
34+
writer.close();
35+
}
36+
catch (exn) {
37+
reader.close();
38+
39+
throw exn;
40+
}
41+
42+
reader.close();
43+
}
44+
```
45+
46+
You could change the above slightly to a single try catch but you then need to do null checks against each class with a close function to check that it was constructed, so neither option is great. I can't speak for everyone but I certaintly don't write code like this so I suspect there's a lot of potentially leaky haxe code out there for failure paths.
47+
48+
The `autoclose` keyword solves this problem for the user by ensuring constructed classes with a `close` function have it executed at the end of the code block or if an exception is thrown.
49+
50+
```haxe
51+
autoclose final reader = File.read("input.txt", false);
52+
autoclose final writer = File.write("output.txt", false);
53+
54+
while (!reader.eof()) {
55+
writer.writeLine(reader.readLine());
56+
}
57+
```
58+
59+
## Detailed design
60+
61+
The `autoclose` keyword can be prefixed to any variable delaration expression where the type contains a public `close` function with a `Void->Void` signature. This allows the keyword to be easily used with all existing closable standard library types and 3rd party libraries without modifications requiring some interface to be implemented.
62+
63+
The try catch nesting as shown in the examples in the previous section will be generated for the user to ensure close is called in normal and exceptional cases.
64+
65+
Null checks should be added before `close` is called and in the case of a null variable no `close` call should be made and no exception thrown. Variables of `Dynamic` should not be allow to use the `autoclose` keyword.
66+
67+
Coroutines support can be added by having `autoclose` also be allowed on variable of types which have a `close` coroutine function of type `Void->Unit`. If a class has both a `Void->Void` and coroutine `Void->Unit` function the coroutine one should be used if the variable is declared in a coroutine.
68+
69+
A new `VAutoClose` tvar flag could be added to indicate if a declaration is an autoclose one.
70+
71+
## Impact on existing code
72+
73+
There should be no breaking runtime changes with this proposal, but the introduction of `autoclose` may cause issues with existing code bases with variables of the same name.
74+
75+
## Drawbacks
76+
77+
This auto closing hides the `close` call which can make debugging trickier if you want to step into the function. A large number of `autoclose` variables in a given scope could also lead to many try catches which can be expensive depending on the target.
78+
79+
## Alternatives
80+
81+
The try catch transformation can be done by a build macro and a `:autoclose` metadata quite easily (https://gist.github.com/Aidan63/3ff8baf8cdad659a3bd1750cd751825e), but having it part of the language means it will see greater use and lead to higher quality (less leaky) libraries due to the ease of resource management.
82+
83+
## Unresolved questions
84+
85+
I don't have any strong feelings about the `autoclose` name, so if anyone else has any suggestions for a better / less likely to cause conflicts name then please suggest.
86+
87+
We may want to allow generators to opt out of the try catch transformation as the target may have a native equivilent. E.g. java 8+ has try resources, C# IDisposable / using, and C++ RAII. These assumably perform better than try catches so it may be useful to allow generators to implement using those.
88+
89+
I went for the structural typing way where anything with a Void->Void close function can be used instead of requiring an interface. Many existing classes in the standard library which would benefit from this are tagged as extern classes so it may not be easy go back and have them implement an interface. We do lose the ability to have stuff like `Array<IClosable>` without resorting to structural typing which is dynamic on many targets. I'm open to reconsidering this if anyone feels strongly.

0 commit comments

Comments
 (0)