Live data from Hacker News

The Defer Technical Specification: It Is Time

thephd.dev

1–10 of 77 posts

Re: The Defer Technical Specification: It Is Time

#4
Ugh.

Go's "defer" is reasonably clean because Go is garbage-collected. So you don't have to worry about something being deleted before a queued "defer" runs. That's well-behaved. This is going to be full of ugly, non-obvious problems.

Interestingly, it's not really "defer" in the Go sense. It's "finally", in the try/finally sense of C++, using Go-type "defer" syntax". This mostly matters for scope and ownership issues. If you want to close a file in a defer, and the file is a local variable, you have to be sure that the close precedes the end of block de-allocation. Most of the discussion in the article revolves around how to make such problems behave halfway decently.

"defer" happens invisibly, in the background. That's contrary to the basic simplicity of C, where almost nothing happens invisibly.

Re: The Defer Technical Specification: It Is Time

#5
post #4

Ugh. Go's "defer" is reasonably clean because Go is garbage-collected. So you don't have to worry about something being deleted before a queued "defer" runs. That's well-behaved. This is going to be full of ugly, non-obvious problems. Interestingly, it's not really "defer" in the Go sense. It's "finally", in the try/finally sense of C++, using Go-type "defer" syntax". This mostly matters for scope and ownership issue…

The point of defer is to put the cleanup logic in one place for local variables though, so the risk of someone else deleting it isn't a thing.

Re: The Defer Technical Specification: It Is Time

#6
> The central idea behind defer is that, unlike its Go counterpart, defer in C is lexically bound, or “translation-time” only, or “statically scoped”. What that means is that defer runs unconditionally at the end of the block or the scope it is bound to based on its lexical position in the order of the program.

The only reasonable way for defer to behave. Function scoped never made sense to me given the wasted potential. The demonstration with loop and mutex being a good one.

Re: The Defer Technical Specification: It Is Time

#7
Regarding the statements on golang's defer:

  "the defer call is hoisted to the outside of the for loop in func work"
Astonishing. Add that to the list of golang head scratchers. That is one of the biggest "principle of least astonishment" violations I've ever seen.

Disclaimer: Not a golang hater. Great language. Used it myself on occasion, although I remain a golang neophyte. Put away the sharp objects.

Re: The Defer Technical Specification: It Is Time

#8
post #4

Ugh. Go's "defer" is reasonably clean because Go is garbage-collected. So you don't have to worry about something being deleted before a queued "defer" runs. That's well-behaved. This is going to be full of ugly, non-obvious problems. Interestingly, it's not really "defer" in the Go sense. It's "finally", in the try/finally sense of C++, using Go-type "defer" syntax". This mostly matters for scope and ownership issue…

[deleted]

Re: The Defer Technical Specification: It Is Time

#9
Another cool difference between this and Go’s ‘defer’, is that it doesn’t allocate memory on the heap. Go’s ‘defer’ does and it has a small performance cost compared to just calling the .release() or whatever yourself… shrugs

At least this was the case last I did benchmarks of my Go code. Dno if they changed that.

Re: The Defer Technical Specification: It Is Time

#10
What is the recommended way to use defer to free values only on an error path (rather than all paths)? Currently I use goto for this:

    void* p1 = malloc(...);
    if (!p1) goto err1;
    void* p2 = malloc(...);
    if (!p2) goto err2;
    void* p3 = malloc(...);
    if (!p3) goto err3;

    return {p1, p2, p3};

    err3: free(p2);
    err2: free(p1);
    err1: return NULL;
With defer I think I would have to use a "success" boolean like this:

    bool success = false;

    void* p1 = malloc(...);
    if (!p1) return NULL;
    defer { if (!success) free(p1) }

    void* p2 = malloc(...);
    if (!p2) return NULL;
    defer { if (!success) free(p2) }

    void* p3 = malloc(...);
    if (!p3) return NULL;
    defer { if (!success) free(p3) }

    success = true;
    return {p1, p2, p3};
I'm not sure if this has really improved things. I do see the use-case for locks and functions that allocate/free together though.
Post reply on HN