Live data from Hacker News

The Defer Technical Specification: It Is Time

thephd.dev

61–70 of 77 posts

Re: The Defer Technical Specification: It Is Time

#61
post #47

Earlier quoted context omitted.

That's what it does in Go too. This is totally defer in the Go sense (except they fixed the scoping issue).

Not quite. "The central idea behind defer is that, unlike its Go counterpart, defer in C is lexically bound, or “translation-time” only, or “statically scoped”" Defer in Go puts the deferred action on a run time to-do list that's processed at function exit. You can queue up deferred actions from a loop in Go. Not in this proposal for C. What happens in this C proposal if you put a defer request inside a loop? Is it a…

Yes maybe you didn't get to the end of my one-sentence comment but I did say

> except they fixed the scoping issue

> What happens in this C proposal if you put a defer request inside a loop?

It executes at the end of the loop body.

Re: The Defer Technical Specification: It Is Time

#62
post #47

Earlier quoted context omitted.

Not quite. "The central idea behind defer is that, unlike its Go counterpart, defer in C is lexically bound, or “translation-time” only, or “statically scoped”" Defer in Go puts the deferred action on a run time to-do list that's processed at function exit. You can queue up deferred actions from a loop in Go. Not in this proposal for C. What happens in this C proposal if you put a defer request inside a loop? Is it a…

Loops in C introduce a new lexical scope, so the defer runs once for every loop iteration. Assuming you are using defer for destructor purposes, and use it where you declare your variable, this would generally be what you want, as it frees the memory at the same time it goes out of scope. The flip side of this is that code like the following would be broken: char *foo = NULL; if (true) { foo = calloc(1,1); defer { fr…

That particular example is easy - just put the defer before the if.

Re: The Defer Technical Specification: It Is Time

#63
post #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.

Say that the defer would execute inside for loops, what would make you more astonished: loops and functions are the exceptions, or defers execute at the end of any block? I would prefer the latter of these two. But then the consequence is that a defer in an if-block executes instantly, so you cannot conditionally defer anymore. So it seems that the rules for when deferees execute need to be arbitrary, and "only functions" seems fewer exceptions than "only functions and loops", isn't it? And what about loops implemented through gotos? Oh boy.

Re: The Defer Technical Specification: It Is Time

#64
post #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.

Say that the defer would execute inside for loops, what would make you more astonished: loops and functions are the exceptions, or defers execute at the end of any block? I would prefer the latter of these two. But then the consequence is that a defer in an if-block executes instantly, so you cannot conditionally defer anymore. So it seems that the rules for when deferees execute need to be arbitrary, and "only funct…

> a defer in an if-block executes instantly, so you cannot conditionally defer anymore.

Of course you can, using ?: (or && and || if you prefer), just like any other case where you want an expression rather than a statement. Or simply using the non-block form of if. (Some stupid autoformatters or tech leads insert extraneous braces, but you should be avoiding those already).

Re: The Defer Technical Specification: It Is Time

#65
post #31

The author takes great care to rebut a common theme among objections to the proposal - “this isn’t necessary if you just write code better”. I am reminded of this fantastic essay: > If we flew planes like we write code, we’d have daily crashes, of course, but beyond that, the response to every plane crash would be: “only a bad pilot blames their plane!” > This doesn’t happen in aviation, because in aviation we have d…

> they are traumatized by writing executable YAML

It gives me solace to know that I am not alone.

Re: The Defer Technical Specification: It Is Time

#66
post #59
post #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.

My biggest astonishment is how people continue to shoot themselves in the foot by not making scope vs function declarations explicit. For the reasons that “someone will misunderstand complicated ideas, so let’s make it implicit” or something. While there could be just: defer x // scope scoped defer fn x // function scoped Also: var a = 0 fn var a = 0 for fn i := … But we have this allergy to full control and invent t…

I wouldn't want my life turned into an embedded block, whatever that is.

Re: The Defer Technical Specification: It Is Time

#67
post #64

Earlier quoted context omitted.

Say that the defer would execute inside for loops, what would make you more astonished: loops and functions are the exceptions, or defers execute at the end of any block? I would prefer the latter of these two. But then the consequence is that a defer in an if-block executes instantly, so you cannot conditionally defer anymore. So it seems that the rules for when deferees execute need to be arbitrary, and "only funct…

> a defer in an if-block executes instantly, so you cannot conditionally defer anymore. Of course you can, using ?: (or && and || if you prefer), just like any other case where you want an expression rather than a statement. Or simply using the non-block form of if. (Some stupid autoformatters or tech leads insert extraneous braces, but you should be avoiding those already).

The parent I was replying to was talking about Go. There is no ternary operator in Go. There are no non-block forms of if in Go. I'm not sure what your "of course" is referring to, but I guess it is unrelated.

Re: The Defer Technical Specification: It Is Time

#68
The TS doesn't seem to provide for a way to modify return values for the function. For example the following is a common pattern in Go using defer to ensure that errors closing a writeable file are returned:

    func foo() (retErr error) {
        f, err := os.Create("out.txt")
        if err != nil {
            return fmt.Errorf("error opening file: %w", err)
        }
        defer func() {
            err := f.Close()
            if err != nil && retErr == nil {
                retErr = fmt.Errorf("error closing file: %w", err)
            }
        }()
        _, err = f.Write([]byte("hello world!"))
        return err
    }

Re: The Defer Technical Specification: It Is Time

#69
post #38
post #31

The author takes great care to rebut a common theme among objections to the proposal - “this isn’t necessary if you just write code better”. I am reminded of this fantastic essay: > If we flew planes like we write code, we’d have daily crashes, of course, but beyond that, the response to every plane crash would be: “only a bad pilot blames their plane!” > This doesn’t happen in aviation, because in aviation we have d…

I agree with that, but: - the language still allows you write the unsafe version even with defer. By your logic fallible humans will continue to write these class of bugs because they can. - adding a whole new flow control construct will introduce a whole new class of bugs. The dog barking example is cool for demonstrating how defer works, but is completely unreadable for what it does, programmers will write code lik…

> is completely unreadable for what it does

Maybe I'm putting too much emphasis on "completely unreadable" rather than the rest of the quotation, but I find the example crystal clear, and I'd never expect code intended to illustrate, clearly and loudly, language features to read naturally.

> to make a language safer you should remove the things that make unsafe behavior possible, not add constructs which make safe behavior easier.

Some of this guy's other (equally superb) blog posts explain why this isn't an option: it breaks decades' worth of C code, and the C standards group is strongly committed to ensuring that C that compiled 20, 30, 40 years ago continues to compile.

Regardless, I find it incredibly weird to read the statement "you should [...] not add constructs which make safe behavior easier," no matter the contents of "[...]." If your goal is to improve the security of a programming language or the maintainability of code in that language, and you don't want breaking changes, this isn't just your best option. It's your only option, I think.

Re: The Defer Technical Specification: It Is Time

#70
post #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.

Say that the defer would execute inside for loops, what would make you more astonished: loops and functions are the exceptions, or defers execute at the end of any block? I would prefer the latter of these two. But then the consequence is that a defer in an if-block executes instantly, so you cannot conditionally defer anymore. So it seems that the rules for when deferees execute need to be arbitrary, and "only funct…

> so you cannot conditionally defer anymore.

I think you can, for example this way:

- declare a function pointer variable cleanup - initialize it with no_op - call defer ‘call cleanup’ - if, inside a block, you realize that you want to do something at cleanup, set cleanup to another function

That’s more code, but how frequent is it that one wants to do that?

One thing this doesn’t support is having a call into third party code defer cleanup to function exit time. Does golang supports that?

Post reply on HN