Difference with function returning struct and function returning pointer to struct

82 views
Skip to first unread message

Orson Cart

unread,
Nov 20, 2019, 12:42:03 PM11/20/19
to golang-nuts

I'm a newbie to Go having used C and C++ in the past and I'm puzzled about something I've just seen.

In the following code getEmployee returns a pointer to a struct. The return value is then dereferenced. This code compiles and runs fine:

package main

type employee struct {
ID   int
name string
}

var dilbert employee

func main() {

getEmployee().name = "dilbert"
}

func getEmployee() *employee {
return &dilbert
}

However if I modify getEmployee as follows, I get a compilation error:

func getEmployee() employee {
return dilbert
}

The error is: cannot assign to getEmployee().name

I assume that it revolves around "assignability" but I'm struggling to understand why.

Can anyone tell me why this is?

TIA,
Orson


Thomas Bushnell, BSG

unread,
Nov 20, 2019, 12:55:00 PM11/20/19
to Orson Cart, golang-nuts
You can only assign to something which is addressable in the sense of https://golang.org/ref/spec#Address_operators.

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."

You want "a field selector of an addressable struct operand", but the return value of a function is not addressable (it's not a variable, pointer, etc etc).

By contrast, in the case where your function returns a pointer, then the struct is the result of a pointer indirection (so it's addressable) and the field selection is thus addressable too.

Thomas




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/aaead2ec-b5b8-48d0-80e5-5275eeb583c2%40googlegroups.com.

Ian Lance Taylor

unread,
Nov 20, 2019, 12:55:59 PM11/20/19
to Orson Cart, golang-nuts
There are two kinds of answers.

One is that the spec only permits setting fields of a struct that is
addressable, and the result of a function call is not addressable.
See https://golang.org/ref/spec#Assignments and
https://golang.org/ref/spec#Address_operators .

The other kind of answer is that if a function returns a pointer to a
struct, a value of type *employee, then it's normal for that something
else to have a copy of that pointer, perhaps some data structure or
global variable. In your simple example that is the global variable
"dilbert". So it makes sense to permit setting a field of the result
of calling getEmployee(), a value of type *employee, as setting that
field will change the global variable "dilbert". But when
getEmployee() does not return a pointer, but just returns a value of
type "employee", then that is a copy of the value in the global
variable. Changing a field in that copy won't change anything. The
assignment will be made, and then the result will be discarded. Since
that operation is useless, the language does not permit it.

Ian

Orson Cart

unread,
Nov 20, 2019, 3:12:33 PM11/20/19
to golang-nuts
On Wednesday, 20 November 2019 17:55:00 UTC, Thomas Bushnell, BSG wrote:
<snip>
but the return value of a function is not addressable (it's not a variable, pointer, etc etc).
</snip>

Hi Thomas. Apologies, I said "assignable" when I meant "addressable". I was curious as to why a struct returned from a function is not addressable but I understand now.

Thanks for your prompt reply.

Orson Cart

unread,
Nov 20, 2019, 3:16:39 PM11/20/19
to golang-nuts
On Wednesday, 20 November 2019 17:55:59 UTC, Ian Lance Taylor wrote:
The other kind of answer is that if a function returns a pointer to a
struct, a value of type *employee, then it's normal for that something
else to have a copy of that pointer, perhaps some data structure or
global variable.  In your simple example that is the global variable
"dilbert".  So it makes sense to permit setting a field of the result
of calling getEmployee(), a value of type *employee, as setting that
field will change the global variable "dilbert".  But when
getEmployee() does not return a pointer, but just returns a value of
type "employee", then that is a copy of the value in the global
variable.  Changing a field in that copy won't change anything.  The
assignment will be made, and then the result will be discarded.  Since
that operation is useless, the language does not permit it.

 Hi Ian and thanks for your prompt reply. This is exactly the kind of explanation that I was looking for and it makes complete sense now.

Robert Engels

unread,
Nov 20, 2019, 3:26:26 PM11/20/19
to Ian Lance Taylor, Orson Cart, golang-nuts

To be honest, I find this very confusing, especially the statement "Changing a field in that copy won't change anything." because even if I have a copy, I should be able to change the fields, and the changes would be there for the scope, and if I returned the copy, whether by address or copy, the changes would be retained.
>The other kind of answer is that if a function returns a pointer to a
>struct, a value of type *employee, then it's normal for that something
>else to have a copy of that pointer, perhaps some data structure or
>global variable. In your simple example that is the global variable
>"dilbert". So it makes sense to permit setting a field of the result
>of calling getEmployee(), a value of type *employee, as setting that
>field will change the global variable "dilbert". But when
>getEmployee() does not return a pointer, but just returns a value of
>type "employee", then that is a copy of the value in the global
>variable. Changing a field in that copy won't change anything. The
>assignment will be made, and then the result will be discarded. Since
>that operation is useless, the language does not permit it.
>
>Ian
>
>--
>You received this message because you are subscribed to the Google Groups "golang-nuts" group.
>To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
>To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAOyqgcVz5oaDa98bXMKS5mKW-ya55dewcrUtmQZcy-v0-YUicg%40mail.gmail.com.

Robert Engels

unread,
Nov 20, 2019, 3:32:23 PM11/20/19
to Robert Engels, Ian Lance Taylor, Orson Cart, golang-nuts
I must of misread something, because this code works fine:

package main

import "fmt"

type X struct {
x int
}

func getX() X {
var x X
return x
}

func main() {
c := getX()
c.x = 1
fmt.Println(c)
}

and is what I would expect to happen. Why is this not the same behavior in the other code?
>To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/842040269.1664.1574281551187%40wamui-scooby.atl.sa.earthlink.net.

Robert Engels

unread,
Nov 20, 2019, 3:33:35 PM11/20/19
to Robert Engels, Ian Lance Taylor, Orson Cart, golang-nuts
Duh, sorry for the spam - I was reading the text without looking at the code. Makes perfect sense.
>To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/2134227176.1691.1574281911663%40wamui-scooby.atl.sa.earthlink.net.

Andrew Klager

unread,
Nov 20, 2019, 3:41:43 PM11/20/19
to Robert Engels, Ian Lance Taylor, Orson Cart, golang-nuts
  c := getX()
  c.x = 1

vs

getX().x = 1


Reply all
Reply to author
Forward
0 new messages