Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm fairly sure that almost every statically typed language has function definitions like that. C, C++, Java, Go, Rust and so on all have that style of function declaration.

Named returns are a Go thing mainly because of defer.



How does defer interact with named returns?


As one would expect. The deferred code runs after the normal code in the function has ended, and before the calling code has resumed. Named return values are in scope and can be read and modified.

Try it and see: https://play.golang.org/p/1ozFWDj15a


Cool. Can anything execute between the end of the deferer and the start of the deferred?


Anything as from any other thread/goroutine? Yes of course, all shared data must be protected from races.

If you mean in the same context then, no.


I'm thinking of it in the way that the interpreter works in JavaScript with tasks. If you setTimeout(A, 0), inside B, then after B returns, A is called, but any other tasks previously inserted into the queue are called first.

So I think that means I was asking about execution in the same context (as in memory context), unless you mean stack frame by context, in which case, I think i understand that because the caller returns the value of the deferred, they are in the same stack frame, and nothing else could insert in that frame between them. I'm not sure you know what i mean, but do i have it about right?

I don't really understand this, but i think I'm getting somewhere.


It's much simpler than that. It's just a way of defining cleanup functions without having a language-level concept of destructors. Here's an example: https://gobyexample.com/defer.

This simple example should explain everything:

    package main

    import "fmt"

    func function1() {
        defer fmt.Println("function1: defer a")
        fmt.Println("function1: inside")
        defer fmt.Println("function1: defer b")
    }

    func main() {
        fmt.Println("main: before function1")
        function1()
        fmt.Println("main: after function1")
    }
Here is the output:

    main: before function1
    function1: inside
    function1: defer b
    function1: defer a
    main: after function1
All defers run in LIFO order at the point when a function returns before the function returns execution back to the caller.


Got it thanks a lot, that's very clear.


You can easily access and modify the named return variables from a deferred function body.

If you had a variable declared in a block just before return, then you return it, you have no way to modify it in defer.

I personally don't like this style of code, but I can see some uses.


Ok now I got they are in scope. About defer, could you think of it like defer makes a function into a function with multiple entry and exit points, possible to be stopped and resumed, like a coroutine?


Ehm, not sure I understood, but I'd say no. Defer is just code that is executed in reverse order upon return from a fuction. It has nothing to do with coroutines. It's a cleaner way to write the usual C syntax of "goto cleanup_x" code.

Go coroutines (goroutines) are functions invoked with the "go" keyword. These cannot be stopped or resumed, but might be (possibly) executed on a different thread. In any case, they are not guaranteed to be executed immediately in the normal flow of the code.


>Ehm, not sure I understood, but I'd say no. Defer is just code that is executed in reverse order upon return from a fuction.

I'd say more like the equivalent of a "finally" clause (or more) for your whole function.

Though not sure about the "executed in reverse order part" -- what's "in reverse order" about Defer? Except if you mean that multiple defers get executed "last seen first"...


Thanks alot for explaining, I think i get it a bit better now.


defer can refer to and change the return values. This is useful, for example, when the deferred code can trigger an error that one wants to return, https://play.golang.org/p/MBmy9OocAG


Is that actually returning err as the deferred return value of test? In other words, to the caller of test it appears test returns the result of the deferred?


Deferred functions don't return anything. You can modify the values that are returned by the parent function, and those will be returned as the deferred function modified them.


Yep, and one cannot simulate that with local variables. In Go "return v" copies v into the return location before calling the deferred code. If that location is not named, the deferred function has no way to change it, see https://play.golang.org/p/Opg4XI08P7


I got it. That's a neat example. Do you have to define that deferred function inside the caller, in order to reference the name? Or can you factor out deferred functions to be used by various callers and pass in the return names for them to modify?


You can pass a pointer to the named return values to a function defined outside, like in https://play.golang.org/p/5jBKcUCj8C .


Ah, okay, thanks. I get it better now. Sort of like decorators in purpose, then.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: