Resource management (eg. try-with-resources)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Resource management (eg. try-with-resources)

Michał Wadas
After I started writing code  extensively using async-await I have noticed that I would like to have automated way of dealing with resource management.

Scope-level manage was proven (Python, C++, Java at least) to be intuitive and error proof. 

Previous discussion on this topic: https://esdiscuss.org/topic/resource-management

Example syntax:

try with Expression as Identifier {

} catch... finally...

Symbol.open and Symbol.close methods would be called respectively on entering and leaving try block. 

Plays well with both synchronous and asynchronous resource access.

Another option is to reuse with:

with(expression as identifier) {

}

Though it would be confusing to statement with wildly different semantics in strict mode.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Resource management (eg. try-with-resources)

T.J. Crowder-2
On Fri, Nov 10, 2017 at 3:00 PM, Michał Wadas <[hidden email]> wrote:
>
> After I started writing code  extensively using async-await I have noticed that I would like to have automated way of dealing with resource management.

This is something I'd really like to see as well.

What's the motivation for having an `open`? Java's `AutoCloseable` just has `close`; one would normally be acquiring these from a constructor or function, which is effectively the `open`...?

Can you give a concrete example using the syntax you're looking at? E.g., were you really thinking of actually having `with` and `as`? If so, I'd rather steal more directly from Java (perhaps replacing their `;` with `,`):

```js
try (a = giveMeAResource(), b = giveMeAnotherResource()) {
    // `a` and `b` are in scope here
} catch (e) {
    // ...`a` and `b` are not in scope here
} finally {
    // ...`a` and `b` are not in scope here
}
```

...where (off-the-cuff):

* Both `catch` and `finally` are optional
* `a` and `b` are constants scoped to the `try` block (no need for the keyword, but could require or allow it for clarity)
* Trailing commas on the resource declaration/initializer list are fine
* `b[Symbol.close]` is called first, then `a[Symbol.close]`
* Both `close`s are called prior to the execution of code in the `catch` or `finally` (if any)
* If the `try` block throws, that error is the primary error and any `close` calls that also throw are "suppressed errors" (more below)
* If the `try` block doesn't throw, but any `close` calls do, the *first* `close` that fails becomes the primary error; any ohers that fail become suppressed errors

Suppressed error handling:

* If the primary error is an `Error` object, suppressed errors are added to a `suppressed` array property on it (creating it if necessary)
* If the primary error is not an `Error` object, they're lost other than being treated as unhandled errors by the environment (for instance: logged, perhaps causing script termination; thought required on that)

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Resource management (eg. try-with-resources)

Isiah Meadows-2

Here's a C++-inspired alternative:

- `let res = value[Symbol.resource]()` - Get an optional promise to a resource. lf missing, `res` is set to `value` instead.
- `res[Symbol.close]()` - Close a resource, optionally returning a promise.
- `try let res = value` - Get the resource by invoking `value[Symbol.resource]()` (or using `value` if the method is missing), assign it to `res`, and invoke `res[Symbol.resource]()` once it leaves the scope, even on error.
- `try await let res = value` - Same as above, but await `value[Symbol.resource]()` (if necessary) and `res[Symbol.close]()` after calling them.
- `try with expr`, `try await with expr` - Same as above, but without declaring a binding. (Works well with transactions, locks, etc.)
- Close exceptions replace thrown exceptions.

Benefits:

1. Less nesting, more concise.
2. Java's `try`-with-resources is clunky and awkward. Python's `with` statement is no different.
3. It works well with sync and async resources.
4. User-level primitives are easier to write.

Of course, in the spec, there's a few logical cases where you'd want these methods to be defined/used:

- `%IteratorPrototype%[@@close]()` - return `this.close()` if such a method exists.
- `%AsyncIteratorPrototype%[@@close]()` - Similar to above.
- `Atomics.lock(sab, index, size)` - Return a resource that acquires a lock for this section, and releases on `@@close`.


On Fri, Nov 10, 2017, 10:32 T.J. Crowder <[hidden email]> wrote:
On Fri, Nov 10, 2017 at 3:00 PM, Michał Wadas <[hidden email]> wrote:
>
> After I started writing code  extensively using async-await I have noticed that I would like to have automated way of dealing with resource management.

This is something I'd really like to see as well.

What's the motivation for having an `open`? Java's `AutoCloseable` just has `close`; one would normally be acquiring these from a constructor or function, which is effectively the `open`...?

Can you give a concrete example using the syntax you're looking at? E.g., were you really thinking of actually having `with` and `as`? If so, I'd rather steal more directly from Java (perhaps replacing their `;` with `,`):

```js
try (a = giveMeAResource(), b = giveMeAnotherResource()) {
    // `a` and `b` are in scope here
} catch (e) {
    // ...`a` and `b` are not in scope here
} finally {
    // ...`a` and `b` are not in scope here
}
```

...where (off-the-cuff):

* Both `catch` and `finally` are optional
* `a` and `b` are constants scoped to the `try` block (no need for the keyword, but could require or allow it for clarity)
* Trailing commas on the resource declaration/initializer list are fine
* `b[Symbol.close]` is called first, then `a[Symbol.close]`
* Both `close`s are called prior to the execution of code in the `catch` or `finally` (if any)
* If the `try` block throws, that error is the primary error and any `close` calls that also throw are "suppressed errors" (more below)
* If the `try` block doesn't throw, but any `close` calls do, the *first* `close` that fails becomes the primary error; any ohers that fail become suppressed errors

Suppressed error handling:

* If the primary error is an `Error` object, suppressed errors are added to a `suppressed` array property on it (creating it if necessary)
* If the primary error is not an `Error` object, they're lost other than being treated as unhandled errors by the environment (for instance: logged, perhaps causing script termination; thought required on that)

-- T.J. Crowder
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss