One neat feature in Java and C# that I think would be great for Dart is the ability to have a resource be automatically closeable/disposable. This is accomplished in Java with the Closeable and/or AutoCloseable interface paired with the following try-catch syntax:
try (CloseableResource cr = new CloseableResource) {
...
} //optionally add a catch and/or finally branch here
and in C# with the IDisposable and using syntax:
c#
using (IDisposableResource idr = new IDisposableResource()) {
...
}
This helps catch resource leaks because the compiler can detect and warn the developer when close/dispose has not been called or has been called unsafely. I'd love to see this feature in Dart!
Edits: Spelling and grammar fixes
You could easily accomplish this with closures in Dart as-is:
abstract class Resource {
void dispose();
}
void using<T extends Resource>(T resource, void Function(T) fn) {
fn(resource);
resource.dispose();
}
Example use:
main() {
using(new FileResource(), (file) {
// Use 'file'
});
}
It's unlikely this will be added in the language, since unlike Java there is a good way to create your own syntaxes/DSLs with closures today. For some examples, you could look at package:pool, which is sort of built around this idea:
// Create a Pool that will only allocate 10 resources at once. After 30 seconds
// of inactivity with all resources checked out, the pool will throw an error.
final pool = new Pool(10, timeout: new Duration(seconds: 30));
Future<String> readFile(String path) {
// Since the call to [File.readAsString] is within [withResource], no more
// than ten files will be open at once.
return pool.withResource(() => new File(path).readAsString());
}
For what it's worth, your example is doable in Java/C# if the using function existed on a class (it could even be a static function). The main reason for making it a part of the language is that it allows tools (in Dart's case the analyzer) to ensure that a resource is properly closed and warn the developer if it isn't. This is extremely useful for large-scale projects, especially ones with entry level engineers on it, and the "build your own" approach doesn't allow for it. Alternatively, the analyzer could warn when any class with a close function never has it called, but without the contractual/spec obligation it would only be guessing. I also truly think this feature falls in line with three of Dart's core goals: Provide a solid foundation of libraries and tools, Make common programming tasks easy, and Be the stable, pragmatic solution for real apps. I really hope you reconsider adding this feature. It's not a "must-have", but it's definitely a "nice-to-have" that can help the language stand out a little more and provide some nice polish.
I can see that Matan's approach will do almost exactly what was requested in this issue, but I still have this nagging suspicion that there could be more to resource finalization than this, and this issue could serve to clarify the situation. With that in mind, I'll reopen this issue and mark it with new labels. Of course, there is no guarantee that we will accept such a language enhancement proposal in the end.
I am new to Dart, but I am experienced in C# and in Java, and as far as I can see @matanlurey example will not be the same as in Java's try with resources or C#'s using.
It all boils down to Exception handling. If an Exception is thrown inside Matan's using() method, that Resource will never be disposed. Whereas in Java and in C#, the language surrounds everything with a try-finally so no matter what happened inside the execution block, the Resource is disposed at the finally block added by the language.
Java also takes care to not suppress any Exception thrown inside the finally block.
I think a feature like this is very welcome to the language, since it makes coding simpler and less error prone to forget to close/dispose a resource, specially on edge cases where Exception may arise inside a try and/or a finally block, like with database and network connections.
EDIT:
I found this autoClose method, it solves this (although I don't think the error handling will be as elegant as in a try with resources from Java), I just don't get why there's a null check for the autoCloseable and not one for the action.
To put code in @matanlurey's mouth
void using<T extends Resource>(T resource, void Function(T) fn) {
try {
fn(resource);
} finally {
resource.dispose();
}
}
The issue with this approach: you pay for a closure which could be avoided it this was a language feature.
Yes, and I am not experienced enough in Dart to state safely what's going to happen if resource.dispose() throws an Exception itself.
I believe that even if you make a catch() and pass an onError closure, as autoClose does, we would also have to surround this whole code with a try-catch, only to get any Exception thrown inside the finally clause, making this whole code very cumbersome and prone to error...am I wrong?
If this is the case, then having a try with resources that catch Exception thrown inside the creation of the Resource, the execution of the computation or the closing of the Resource inside a finally could make things a lot simpler and safer.
If we were to add this to the language, I think we should do something a little more flexible than C# and Java and have it scoped to the lifetime of a variable. When you have multiple resources that need to be guarded, you get a pyramid of braces, which gets unwieldy:
```c#
using (var a = new DisposableA()) {
using (var b = new DisposableB()) {
using (var c = new DisposableC()) {
...
}
}
}
C# lets you omit the braces, which helps when you have *sequential* resources:
```c#
using (var a = new DisposableA())
using (var b = new DisposableB())
using (var c = new DisposableC()) {
...
}
But it falls apart if you need to do anything between those using statements:
```c#
using (var a = new DisposableA())
if (a.Something()) return;
using (var b = new DisposableB())
if (b.AnotherThing()) return;
using (var c = new DisposableC()) {
...
}
This either doesn't compile or, if it does, doesn't do what you want. If we're going to do something analogous in Dart, I think we should jump right ahead to [what C# is adding with `using` on variable declarations](https://github.com/dotnet/csharplang/pull/1703/files):
```c#
using var a = new DisposableA();
if (a.Something()) return;
using var b = new DisposableB();
if (b.AnotherThing()) return;
using var c = new DisposableC();
...
With that, the resource is disposed when the variable goes out of scope. I think it's a much cleaner, more expressive syntax and follows C++'s RAII thing. I don't have a proposal for what syntax we should use for Dart , but something roughly analogous should work.
It's been awhile since I've written any Java, but IIRC you can put multiple Closeable resources in the same try block and they will be closed in reverse order.
try (
CloseableA a = new CloseableA();
CloseableB b = new CloseableB();
CloseableC c = new CloseableC()
) {
...
}
Most helpful comment
If we were to add this to the language, I think we should do something a little more flexible than C# and Java and have it scoped to the lifetime of a variable. When you have multiple resources that need to be guarded, you get a pyramid of braces, which gets unwieldy:
```c#
using (var a = new DisposableA()) {
using (var b = new DisposableB()) {
using (var c = new DisposableC()) {
...
}
}
}
But it falls apart if you need to do anything between those using statements:
```c#
using (var a = new DisposableA())
if (a.Something()) return;
using (var b = new DisposableB())
if (b.AnotherThing()) return;
using (var c = new DisposableC()) {
...
}
With that, the resource is disposed when the variable goes out of scope. I think it's a much cleaner, more expressive syntax and follows C++'s RAII thing. I don't have a proposal for what syntax we should use for Dart , but something roughly analogous should work.