Naming the return value in the function signature will both allocate the named variable, as well as make it the default variable to return.
Returning a new unnamed variable for every return will cause all of the unnamed variables to be allocated.
It's interesting, I don't use this feature of the language... my default way to write this would have been:
func NoNamedReturnParams(i int) (*objectInfo) {
obj := &objectInfo{}
if i == 1 {
// Do one thing
return obj
}
if i == 2 {
// Do another thing
return obj
}
if i == 3 {
// Do one more thing still
return obj
}
// Normal return
return obj
}
I had a bit of a play around with it. It's pretty powerful being able to see <func name> <params type> <return type> in one line ( or possibly multi line )
It really hammers home the concept that a function is a transformation, and of what into what. And I think this syntax would probably encourage pure functions. And it's so useful to allocate the return in the top line. I really like go.
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.
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.
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.
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"...
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?
K&R C had implied type of 'int' for both arguments and return value, and didn't list the types of arguments on the line specifying function name, argument names and return type:
int foo(x,y)
{
return baz(x,y);
}
bar(x,y,z)
short x;
int z;
{
return x+y+z;
}
baz(x,y,z)
{
return 42;
}
Returning a new unnamed variable for every return will cause all of the unnamed variables to be allocated.
It's interesting, I don't use this feature of the language... my default way to write this would have been: