11

Is there a reason for this behaviour? I would like to know what is different in the memory level. The compiler returns "cannot take the address of composite literal" while i can explicitly ask it to do it.

Heres the go playground go playground link

u := User{"john"}
fmt.Println(u.Name()) //implicit

//fmt.Println(User{"john"}.Name()) //Error: cannot call pointer method on composite literal, cannot take the address of composite literal
fmt.Println((&User{"jim"}).Name()) //explicit

type User struct {
    name string
}

func (u *User) Name() string {
    return u.name
}
Gnani
  • 455
  • 5
  • 18

2 Answers2

13

Because a composite litteral is not addressable until it's been assigned to a variable:

The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array.
As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

You can take the address to User{"jim"}: (&User{"jim"}) (literal pointer).
But you cannot directly use the value of User{"jim"} (literal value, not until it is assign to a variable).
See more in this thread.


This thread adds to the"Expression isn't addressable" issue:

Taking the address of something, that up to this hypothetical point was not addressable (an expression that doesn't happen to be rooted to an identifier), is semantically no different then setting the dereferenced value of the destination pointer.
In other words, the following are equivalent:

var x *int
*x = (2 * 3) + 4

var x *int
x = &((2 * 3) + 4)

Since an expression is thrown away as soon as it's used, the address of its value (which often is entirely register-resident, and thus doesn't actually have an address) is entirely meaningless in any case, and the only benefit from taking it's address is the syntactic convenience of type-inference in variable declarations (saving at most a single line):

x := &((2 * 3) + 4)

A problem with making arbitrary expressions addressable:

m := map[int]int{1:2}
x := &m[1]
x = 3
fmt.Println("x is", x, "while m[1] is", m[1])
// will print `x is 3 while m[1] is 2`

In short: it'll be unclear (and nigh impossible to debug) whether you're taking the address of something you expect to be addressable, or when you're taking the address of an implicit intermediate var (which is very often what you don't want).

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • "Because a composite litteral is not addressable until it's been assigned to a variable" I would like to know why. The thread does not give satisfying reasoning/argument. – Gnani Sep 01 '14 at 09:34
  • 1
    @Gnani because the literal value itself isn't directly addressable. &CompiteLiteral is. – VonC Sep 01 '14 at 09:35
2

Is there a reason for this behaviour?

The reason for the behavior is that there is an exception to addressability for that specific notation and the reason for that exception is explained here by one of the Go maintainers :

They're special because we decided that the notation was useful enough for constructors to merit a special case:

Taking the address of a composite literal (§Address operators) 
generates a unique pointer to an instance of the literal's value. 

http://golang.org/doc/go_spec.html#Composite_literals

Russ


"Taking the address of a composite literal (§Address operators) generates a unique pointer to an instance of the literal's value." Could you elaborate that?

I think that means the notation &Object{} notation is simply a literal pointer each time it is executed it creates a new instance of the value and a new pointer is created that points to the new value. The addressability exception simply results from the notation of this literal, it is unlike the other addressables because it is not being acted upon by the & operator.

I would like an answer similar to jesse's on the "here" link you mentioned. That is for C. Can anyone confirm that for golang?

My guess is this that this notation is helpful with escape analysis, which determines at compile time whether a references escapes the function and determines whether it should be allocated on the heap or the stack ( faster ). From what I understand the variables that have their address taken are considered candidates for escape analysis. Since one of Go's main goals is fast compilation I think reference creation and tracking is required to be clear.

For example, for Item{}.Method() the need to create a pointer and therefore run escape analysis to the Item{} value would depend on the receiver type of the Method() whether it is *Item or just Item this unnecessarily complicates compilation. That's why you use the explicit notation &Item{} to construct a *Item.

Emil Davtyan
  • 13,808
  • 5
  • 44
  • 66
  • "Because its an exception" is not agreeable. "Taking the address of a composite literal (§Address operators) generates a unique pointer to an instance of the literal's value." Could you elaborate that? I would like an answer similar to jesse's on the "here" link you mentioned. That is for C. Can anyone confirm that for golang? – Gnani Sep 01 '14 at 09:39
  • @Gnani I added some possible explanations. – Emil Davtyan Sep 01 '14 at 10:12
  • Summarizing VonC: values of variables aren't always at stable heap addresses; they might be in registers, be on the stack and get blown away after the function returns, or might be map values that are moved around in memory as the map grows. – twotwotwo Sep 01 '14 at 21:26
  • In those cases, the Go authors didn't want to make the & operator allocate a stable heap address and copy the result of your expression into it. For one thing, they like to avoid non-obvious heap allocations (hence, say, `make()` to make them explicit). For another, it would, as VonC said, make it *look* like you could take the address of a movable map key, then you later try to update it and discover to your dismay you just copied the key and took the value of that, and aren't updating the value in the map at all--I'd hate to have to debug that one. – twotwotwo Sep 01 '14 at 21:28
  • But they figured `&User{...}` was handy as shorthand for the common pattern of doing `new(User)` then setting values of user fields, and it's intuitive that an object literal will allocate an object, so they thought that case was worthy of an exception to the rule. The connection may not be syntactically obvious, but `[]byte{...}` and `map[string]int{...}` are similar exceptions: instead of replacing `new`-and-initialize, they replace `make`-and-initialize. The pointers involved there are part of the internal representation of the slice/map. – twotwotwo Sep 01 '14 at 21:28