Taking the address of the return value of a function

4,317 views
Skip to first unread message

Daniel Smith

unread,
Mar 8, 2010, 11:31:08 PM3/8/10
to golang-nuts
Am I wrong to expect the following code to compile? (http://ideone.com/URIQ0xZO)

Even if I change "printFoo(&getFoo())" to "printFoo(&(getFoo()))", it still complains that it "cannot take the address of getFoo()". If I first assign it to a temporary variable, then it works.

package main

import (
    "fmt"
)

type foo struct {
    i int
    j int
}

func getFoo() foo {
    return foo{5, 6}
}

func printFoo(f *foo) {
    fmt.Printf("(%d, %d)\n", f.i, f.j)
}

func main() {
    printFoo(&getFoo())
}


--
Daniel Smith
http://www.schaumburggoclub.org/

Kevin Ballard

unread,
Mar 8, 2010, 11:32:49 PM3/8/10
to dan...@lukenine45.net, golang-nuts
You can't take the address of a function's result. You need to store
it in a local variable first, otherwise what are you taking the
address of? Think of it this way - when the function returns, the
result is stored in a register. You can't take the address of a
register. You need to put it into main memory first.

-Kevin Ballard

--
Kevin Ballard
http://kevin.sb.org
kbal...@gmail.com

Daniel Smith

unread,
Mar 9, 2010, 12:02:22 AM3/9/10
to Kevin Ballard, golang-nuts
Why shouldn't I expect the compiler to do that (make a temporary variable and take its address) for me? It does in C++ (well, taking a temporary's address in C++ is of course a very bad idea, but go ought to put the temporary on the heap if I do such a thing).

And anyway, while this particular struct may indeed fit in a register (on a 64 bit machine), many will not, so that doesn't seem like a great reason.

Russ Cox

unread,
Mar 9, 2010, 1:15:43 AM3/9/10
to dan...@lukenine45.net, golang-nuts
On Mon, Mar 8, 2010 at 21:02, Daniel Smith <dan...@lukenine45.net> wrote:
> Why shouldn't I expect the compiler to do that (make a temporary variable
> and take its address) for me? It does in C++ (well, taking a temporary's
> address in C++ is of course a very bad idea, but go ought to put the
> temporary on the heap if I do such a thing).

C++ doesn't let you do this either.
You can only take the address of something that
can be assigned to, and just like you can't say

f() = 1

you can't use &f() either.

$ n x.c
1 int f() { return 0; }
2 int *g() { return &f(); }
$ gcc x.c
x.c: In function 'g':
x.c:2: error: invalid lvalue in unary '&'
$ n x.cc
1 int f() { return 0; }
2 int *g() { return &f(); }
$ gcc x.cc
x.cc: In function 'int* g()':
x.cc:2: error: invalid lvalue in unary '&'
$

Russ

Daniel Smith

unread,
Mar 9, 2010, 2:34:26 AM3/9/10
to golang-nuts
You can definitely take the address of a temporary, see below. It doesn't make a temporary for an int, so you can't take its address.

(This code gives a warning but does indeed compile and run as expected.) http://ideone.com/Visr2JFA

#include <iostream>
 
class foo
{
public:
    int a;
    int b;
};
 
foo getFoo()
{
    foo f;
    f.a = 7;
    f.b = 8;
    return f;
}
 
 
int main()
{
    foo *fp = 0;
    fp = &getFoo();
   
    std::cout << fp->a << fp->b;
    return 0;
}


prog.cpp: In function ‘int main()’:
prog.cpp:22: warning: taking address of temporary

output: 78

Daniel Smith

unread,
Mar 9, 2010, 2:51:53 AM3/9/10
to r...@golang.org, golang-nuts
Well, I had an argument as to why it should work in go even if it didn't in C++ (see my last email), but in writing it I realized that the syntax is impossible if the function returns more than one value, something (obviously) not possible in C++. Hm. That changes everything. I would consider it an ugly hack if you could take the address of the return value of a function which returned a single parameter but not one which returned multiple parameters. Since it doesn't make sense to take the address of multiple parameters (unless they were packed together in some sort of a tuple type), I guess I will just have to live with this.

On Tue, Mar 9, 2010 at 12:15 AM, Russ Cox <r...@golang.org> wrote:

Steven

unread,
Mar 9, 2010, 10:19:17 PM3/9/10
to golang-nuts
Not a very good argument. You can select on a single return and not on a multiple return. You can use a single return in an expression and not a multiple return. You can use a single return for indexing and slicing, but not so with multiple return. The fact is that there is already a gap in that the only things that work with multiple returns are assignments and arguments; the address operator is no exception.

Go does many smart things for you behind the scenes with the only impact being more straightforward code. It automatically decides whether to put something on the stack or the heap, why can't it automatically move something from the register to the heap when you take its address?

Daniel Smith

unread,
Mar 9, 2010, 10:25:38 PM3/9/10
to Steven, golang-nuts
Good point. I was originally going to point out that taking the address of a variable instructs the compiler to store it on the heap, and that, therefore, it's pretty reasonable to interpret taking the address of the return value of a function as an instruction to the compiler to store that return value on the heap.
Reply all
Reply to author
Forward
0 new messages