4 ms·
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 unn
by alexhornbake 9y ago
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
}
- 19eightyfour 9y agoI 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.
- cyphar 9y agoI'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.
- 19eightyfour 9y agoHow does defer interact with named returns?
- Ao7bei3s 9y agoAs 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 https://play.golang.org/p/1ozFWDj15a
- 19eightyfour 9y agoCool. Can anything execute between the end of the deferer and the start of the deferred?
- dullgiulio 9y agoAnything 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.
- 19eightyfour 9y agoI'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.
- cyphar 9y agoIt'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 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.
- dullgiulio 9y agoYou 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.
- 19eightyfour 9y agoOk 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?
- dullgiulio 9y agoEhm, 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.
- coldtea 9y ago>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"...
- 19eightyfour 9y agoThanks alot for explaining, I think i get it a bit better now.
- fpoling 9y agodefer 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 https://play.golang.org/p/MBmy9OocAG
- 19eightyfour 9y agoIs 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?
- dullgiulio 9y agoDeferred 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.
- fpoling 9y agoYep, 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 https://play.golang.org/p/Opg4XI08P7
- 19eightyfour 9y agoI 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?
- fpoling 9y agoYou can pass a pointer to the named return values to a function defined outside, like in https://play.golang.org/p/5jBKcUCj8C https://play.golang.org/p/5jBKcUCj8C .
- ryeguy 9y agoWhat language that has static types doesn't have the func, params, and return type in one line?
- deleted 9y ago[deleted]
- masklinn 9y agoSome HM language can infer types at the toplevel so you may not have an explicit signature at all, although that's generally frowned upon: add1 = map (+1) OTOH they also split the signature and function "header" so that you don't need to remove the "noise" to get the bare signature e.g. add1 :: (Num a) => [a] -> [a] add1 = map (+1)
- KayEss 9y agoC++ ends up with three forms (of course it does): Normal C style declaration int foo() { return 2; } Trailing return type. Useful when the return type depends on the parameter types, or is inside the namespace of the function auto foo() -> int { return 2; } Automated type deduction. Increasingly the choice when possible auto foo() { return 2; }
- Someone 9y agoK&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; }