Proposal: defer keyword

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

Proposal: defer keyword

Ayush Gupta
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta



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

Re: Proposal: defer keyword

Ben Wiley
Hey Ayush,

That's an interesting language feature I hadn't heard of before.

Any reason your use case couldn't be covered by a try/catch in the synchronous case, and a promise.finally() in the async case?

Ben

Le jeu. 20 sept. 2018 05 h 21, Ayush Gupta <[hidden email]> a écrit :
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta


_______________________________________________
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

Ayush Gupta
It can be covered, but then I'll have to duplicate the `connection.release()` call in both the try and catch blocks, (and remember, there can be multiple resources to be cleaned up).

Plus, in case that I have a function with multiple if-else branches with returns from multiple branches, I will have to duplicate that in all the branches.

Another benefit of this is that this will help us logically group allocation and deallocation of resources together, for better readability and debuggability.

On Thu, Sep 20, 2018 at 2:57 PM Ben Wiley <[hidden email]> wrote:
Hey Ayush,

That's an interesting language feature I hadn't heard of before.

Any reason your use case couldn't be covered by a try/catch in the synchronous case, and a promise.finally() in the async case?

Ben

Le jeu. 20 sept. 2018 05 h 21, Ayush Gupta <[hidden email]> a écrit :
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta


_______________________________________________
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

Ben Wiley
If you don't need to do anything in the catch block, you can make it a no-op and put your cleanup statement afterward.

However framing this in terms of a synchronous use case seems odd given that synchronous database operations (your example) are extremely rare and in JavaScript. It seems to me like promises would fit this case pretty well, but I may have missed something.

Ben

Le jeu. 20 sept. 2018 05 h 32, Ayush Gupta <[hidden email]> a écrit :
It can be covered, but then I'll have to duplicate the `connection.release()` call in both the try and catch blocks, (and remember, there can be multiple resources to be cleaned up).

Plus, in case that I have a function with multiple if-else branches with returns from multiple branches, I will have to duplicate that in all the branches.

Another benefit of this is that this will help us logically group allocation and deallocation of resources together, for better readability and debuggability.

On Thu, Sep 20, 2018 at 2:57 PM Ben Wiley <[hidden email]> wrote:
Hey Ayush,

That's an interesting language feature I hadn't heard of before.

Any reason your use case couldn't be covered by a try/catch in the synchronous case, and a promise.finally() in the async case?

Ben

Le jeu. 20 sept. 2018 05 h 21, Ayush Gupta <[hidden email]> a écrit :
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta


_______________________________________________
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

Ayush Gupta
Apologies, I meant to use `async-await` in the example but I missed it.

Also, cleanup can be needed in all code, no matter if it's synchronous, uses promises, callbacks, or `async-await`.  I personally believe that while we can have different mechanisms for doing cleanup  in all different cases, having a single standard mechanism is better.

On Thu, Sep 20, 2018 at 3:09 PM Ben Wiley <[hidden email]> wrote:
If you don't need to do anything in the catch block, you can make it a no-op and put your cleanup statement afterward.

However framing this in terms of a synchronous use case seems odd given that synchronous database operations (your example) are extremely rare and in JavaScript. It seems to me like promises would fit this case pretty well, but I may have missed something.

Ben

Le jeu. 20 sept. 2018 05 h 32, Ayush Gupta <[hidden email]> a écrit :
It can be covered, but then I'll have to duplicate the `connection.release()` call in both the try and catch blocks, (and remember, there can be multiple resources to be cleaned up).

Plus, in case that I have a function with multiple if-else branches with returns from multiple branches, I will have to duplicate that in all the branches.

Another benefit of this is that this will help us logically group allocation and deallocation of resources together, for better readability and debuggability.

On Thu, Sep 20, 2018 at 2:57 PM Ben Wiley <[hidden email]> wrote:
Hey Ayush,

That's an interesting language feature I hadn't heard of before.

Any reason your use case couldn't be covered by a try/catch in the synchronous case, and a promise.finally() in the async case?

Ben

Le jeu. 20 sept. 2018 05 h 21, Ayush Gupta <[hidden email]> a écrit :
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta


_______________________________________________
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

Sultan
What stops you from doing this with try...finally?

function doSomeDbWork() {
    try { return databasepool.getConnection(); } finally { connection.release(); }
}


On Thu, Sep 20, 2018 at 1:01 PM, Ayush Gupta <[hidden email]> wrote:
Apologies, I meant to use `async-await` in the example but I missed it.

Also, cleanup can be needed in all code, no matter if it's synchronous, uses promises, callbacks, or `async-await`.  I personally believe that while we can have different mechanisms for doing cleanup  in all different cases, having a single standard mechanism is better.

On Thu, Sep 20, 2018 at 3:09 PM Ben Wiley <[hidden email]> wrote:
If you don't need to do anything in the catch block, you can make it a no-op and put your cleanup statement afterward.

However framing this in terms of a synchronous use case seems odd given that synchronous database operations (your example) are extremely rare and in JavaScript. It seems to me like promises would fit this case pretty well, but I may have missed something.

Ben

Le jeu. 20 sept. 2018 05 h 32, Ayush Gupta <[hidden email]> a écrit :
It can be covered, but then I'll have to duplicate the `connection.release()` call in both the try and catch blocks, (and remember, there can be multiple resources to be cleaned up).

Plus, in case that I have a function with multiple if-else branches with returns from multiple branches, I will have to duplicate that in all the branches.

Another benefit of this is that this will help us logically group allocation and deallocation of resources together, for better readability and debuggability.

On Thu, Sep 20, 2018 at 2:57 PM Ben Wiley <[hidden email]> wrote:
Hey Ayush,

That's an interesting language feature I hadn't heard of before.

Any reason your use case couldn't be covered by a try/catch in the synchronous case, and a promise.finally() in the async case?

Ben

Le jeu. 20 sept. 2018 05 h 21, Ayush Gupta <[hidden email]> a écrit :
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword name) which would allow   us to "defer" a function which will be executed once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
    const connection = databasepool.getConnection();
    defer function () { connection.release(); } // function would be called no matter when/if the function returns or throws
    //   do your work
}
```

Regards
Ayush Gupta


_______________________________________________
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



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

Re: Proposal: defer keyword

kdex
In reply to this post by Ayush Gupta
So, when is a function supposed to be invoked when `defer`red in a generator?

On Thursday, September 20, 2018 11:21:06 AM CEST Ayush Gupta wrote:

> Hi,
>
> I would like to propose a `defer` keyword(or something else  as the keyword
> name) which would allow   us to "defer" a function which will be executed
> once the current function either returns or throws.
>
> The idea for this is taken from the Go programming language.
>
> It would allow us to perform cleanup activities in a function which has
> multiple branches in a single place.
>
> For example, a sample server side code can look  like:
>
> ```  js
> function doSomeDbWork() {
>     const connection = databasepool.getConnection();
>     defer function () { connection.release(); } // function would be called
> no matter when/if the function returns or throws
>     //   do your work
> }
> ```
>
> Regards
> Ayush Gupta
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

Isiah Meadows-2
Could you chime in with this here as an alternative?
https://github.com/tc39/proposal-using-statement

-----

Isiah Meadows
[hidden email]
www.isiahmeadows.com
On Thu, Sep 20, 2018 at 7:36 AM kdex <[hidden email]> wrote:

>
> So, when is a function supposed to be invoked when `defer`red in a generator?
>
> On Thursday, September 20, 2018 11:21:06 AM CEST Ayush Gupta wrote:
> > Hi,
> >
> > I would like to propose a `defer` keyword(or something else  as the keyword
> > name) which would allow   us to "defer" a function which will be executed
> > once the current function either returns or throws.
> >
> > The idea for this is taken from the Go programming language.
> >
> > It would allow us to perform cleanup activities in a function which has
> > multiple branches in a single place.
> >
> > For example, a sample server side code can look  like:
> >
> > ```  js
> > function doSomeDbWork() {
> >     const connection = databasepool.getConnection();
> >     defer function () { connection.release(); } // function would be called
> > no matter when/if the function returns or throws
> >     //   do your work
> > }
> > ```
> >
> > Regards
> > Ayush Gupta_______________________________________________
> 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
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: defer keyword

kai zhu
how would you handle cleanup after timeouts in https://github.com/tc39/proposal-using-statement?

when managing io-complexity at the integration-level, i feel the reliable/zero-magic/verifiable way to guarantee cleanup in all scenarios is still to use traditional-callbacks, with a timeout-closure.

here are 2 examples using the recursive-callback approach, where cleanup is guaranteed-to-run in the “default” switch-statement; one is real-world [1], and the other is this working, standalone nodejs code:

[1] real-world example of guaranteed cleanup


```js
// example.js
// fully-working standalone code to fetch data from https://api.github.com
// and cleanup afterwards
/*jslint node: true*/
/*property
    GITHUB_TOKEN, authorization, concat, created_at, date, destroy, end, env,
    error, exit, headers, html_url, log, map, on, parse, push, request,
    responseHeaders, responseStatusCode, size, slice, stargazers_count, status,
    statusCode, stringify, updated_at
*/
(function () {
    "use strict";
    var cleanup;
    var chunkList;
    var modeNext;
    var onNext;
    var request;
    var response;
    var timerTimeout;
    cleanup = function () {
        // cleanup timerTimeout
        clearTimeout(timerTimeout);
        // cleanup request-stream
        try {
            request.destroy();
        } catch (ignore) {
        }
        // cleanup response-stream
        try {
            response.destroy();
        } catch (ignore) {
        }
        console.error(
            "\u001b[31mcleaned up request and response streams\u001b[39m"
        );
    };
    onNext = function (error, data) {
        try {
            // guarantee cleanup on callback-error
            if (error) {
                console.error(error);
                modeNext = Infinity;
            }
            modeNext += 1;
            switch (modeNext) {
            case 1:
                // guarantee cleanup after 150000ms timeout
                timerTimeout = setTimeout(function () {
                    onNext(new Error("timeout error"));
                }, 15000);
                // fetch json repository-data from
                // https://api.github.com/tc39/repos
                request = require("url").parse(
                    "https://api.github.com/orgs/tc39/repos"
                );
                request.headers = {};
                request.headers["user-agent"] = "undefined";
                // add optional oauth-token to increase rate-limit quota
                if (process.env.GITHUB_TOKEN) {
                    request.headers.authorization = (
                        "token " + process.env.GITHUB_TOKEN
                    );
                }
                request = require("https").request(
                    request,
                    // concatenate data-chunks from response-stream
                    function (_response) {
                        chunkList = [];
                        response = _response;
                        response
                        .on("data", function (chunk) {
                            chunkList.push(chunk);
                        })
                        .on("end", function () {
                            onNext(null, Buffer.concat(chunkList));
                        })
                        // guarantee cleanup on response-error
                        .on("error", onNext);
                    }
                );
                // guarantee cleanup on request-error
                request.on("error", onNext)
                .end();
                break;
            case 2:
                // print response data
                console.log(JSON.stringify(
                    {
                        responseStatusCode: response.statusCode,
                        responseHeaders: {
                            date: response.headers.date,
                            status: response.headers.status,
                            "content-type": response.headers["content-type"],
                            "content-length": (
                                response.headers["content-length"]
                            )
                        }
                    },
                    null,
                    4
                ));
                // print first 5 results of abridged,
                // JSON.parsed concatenated-data
                console.log(JSON.stringify(
                    JSON.parse(String(data))
                    .slice(0, 5)
                    .map(function (githubRepo) {
                        return {
                            html_url: githubRepo.html_url,
                            created_at: githubRepo.created_at,
                            updated_at: githubRepo.updated_at,
                            size: githubRepo.size,
                            stargazers_count: githubRepo.stargazers_count
                        };
                    }),
                    null,
                    4
                ));
                // guarantee cleanup on successful-operation
                onNext();
                break;
            // cleanup
            default:
                cleanup();
                process.exit(Boolean(error));
            }
        // guarantee cleanup on misc thrown-error
        } catch (errorCaught) {
            onNext(errorCaught);
        }
    };
    modeNext = 0;
    onNext();
}());
```


On 20 Sep 2018, at 11:48 PM, Isiah Meadows <[hidden email]> wrote:

Could you chime in with this here as an alternative?
https://github.com/tc39/proposal-using-statement

-----

Isiah Meadows
[hidden email]
www.isiahmeadows.com
On Thu, Sep 20, 2018 at 7:36 AM kdex <[hidden email]> wrote:

So, when is a function supposed to be invoked when `defer`red in a generator?

On Thursday, September 20, 2018 11:21:06 AM CEST Ayush Gupta wrote:
Hi,

I would like to propose a `defer` keyword(or something else  as the keyword
name) which would allow   us to "defer" a function which will be executed
once the current function either returns or throws.

The idea for this is taken from the Go programming language.

It would allow us to perform cleanup activities in a function which has
multiple branches in a single place.

For example, a sample server side code can look  like:

```  js
function doSomeDbWork() {
   const connection = databasepool.getConnection();
   defer function () { connection.release(); } // function would be called
no matter when/if the function returns or throws
   //   do your work
}
```

Regards
Ayush Gupta_______________________________________________
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


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