Go - I thought Go was a Call by Value language

Here is my code and below that the output - I wrote my question into the output. But to summarize: How can a function modify one of its parameters ie a structure (with slices)? as seen below.

package main

import (
“fmt”
)

type bType struct {
s int // That should read s open square bracket - close square bracket - sorry see supplemental question at bottom
w int
}

func main() {

bOrig := bType{s: []int{11, 12, 13, 14, 15, 16}, w: []int{21, 22, 23, 24, 25, 26}}
bSecond := bOrig

bThird := bType{}
bThird = bOrig
bFourth := bType{}
bFourth = clonebType(bOrig)
fmt.Printf("After Creation\n    bOrig: %v\n", bOrig)
fmt.Printf("  bSecond: %v\n", bSecond)
fmt.Printf("   bThird: %v\n", bThird)
fmt.Printf("   bFourth: %v\n", bFourth)

bSecond.s[2] += 70
bThird.s[4] += 80

fmt.Printf("\nAfter bSecond.s[2] += 70 and bThird.s[4] += 80\n    bOrig: %v\n", bOrig)
fmt.Printf("  bSecond: %v\n", bSecond)
fmt.Printf("   bThird: %v\n", bThird)
fmt.Printf("   bFourth: %v\n", bFourth)
fmt.Printf("\nSIDE QUESTION:\n   OK so I get it, in a structure with slices when copied with a \n      simple = or := the slices still point to the same memory locations. \n      Is that going to be true for primitive types or sub structures of non primitive types?")

fmt.Printf("\n\nPRIMARY QUESTION:\n   Below I pass a structure (bOrig) containing slices to a \n      method that changes part of the slice it then returns nothing.\n      Upon return the structure that was passed reflects the changes made to it in the method.\n      My question is: given this behavior how can Go be called a language that uses\n      CALL BY VALUE???\n\n" +
	"Am I missing something?")

bOrig.methodmessUpbType()

fmt.Printf("\nAfter bOrig.methodmessUpbType()\n    bOrig: %v\n", bOrig)
fmt.Printf("  bSecond: %v\n", bSecond)
fmt.Printf("   bThird: %v\n", bThird)
fmt.Printf("   bFourth: %v\n", bFourth)

}

func clonebType(bIn bType) bType {
var bOut bType
bOut.s = make(int, len(bIn.s))
copy(bOut.s, bIn.s)
bOut.w = make(int, len(bIn.w))
copy(bOut.w, bIn.w)
return bOut
}
// Could not figure out how to install and use go-clone so wrote my own method: clonebType
//Be sure to INSTALL go get GitHub - huandu/go-clone: Clone any Go data structure deeply and thoroughly.
//“github.com/huandu/go-clone/generic”)

func (bIn bType) methodmessUpbType() {
bIn.s[0] += 1000
return
}

And the output:

GOROOT=C:\Users\dan\Dropbox\00 DropBox DAP\Go Language\go1.23.1 #gosetup
GOPATH=C:\Users\dan\go #gosetup
“C:\Users\dan\Dropbox\00 DropBox DAP\Go Language\go1.23.1\bin\go.exe” build -o C:\Users\dan\AppData\Local\JetBrains\GoLand2024.2\tmp\GoLand___go_build_testProject.exe . #gosetup
C:\Users\dan\AppData\Local\JetBrains\GoLand2024.2\tmp\GoLand___go_build_testProject.exe #gosetup
After Creation
bOrig: {[11 12 13 14 15 16] [21 22 23 24 25 26]}
bSecond: {[11 12 13 14 15 16] [21 22 23 24 25 26]}
bThird: {[11 12 13 14 15 16] [21 22 23 24 25 26]}
bFourth: {[11 12 13 14 15 16] [21 22 23 24 25 26]}

After bSecond.s[2] += 70 and bThird.s[4] += 80
bOrig: {[11 12 83 14 95 16] [21 22 23 24 25 26]}
bSecond: {[11 12 83 14 95 16] [21 22 23 24 25 26]}
bThird: {[11 12 83 14 95 16] [21 22 23 24 25 26]}
bFourth: {[11 12 13 14 15 16] [21 22 23 24 25 26]}

SIDE QUESTION:
OK so I get it, in a structure with slices when copied with a
simple = or := the slices still point to the same memory locations.
Is that going to be true for primitive types or sub structures of non primitive types?

PRIMARY QUESTION:
** Below I pass a structure (bOrig) containing slices to a **
** method that changes part of the slice it then returns nothing.**
** Upon return the structure that was passed reflects the changes made to it in the method.**
** My question is: given this behavior how can Go be called a language that uses**
** CALL BY VALUE???**

Am I missing something?

After bOrig.methodmessUpbType()
bOrig: {[1011 12 83 14 95 16] [21 22 23 24 25 26]}
bSecond: {[1011 12 83 14 95 16] [21 22 23 24 25 26]}
bThird: {[1011 12 83 14 95 16] [21 22 23 24 25 26]}
bFourth: {[11 12 13 14 15 16] [21 22 23 24 25 26]}

Process finished with the exit code 0

My conclusion is that structures and slices are actually pointers? Or is this too simple an explanation? But still Call by Value?

Supplemental question - I pasted the code and output but as you can see it broke the listing up. Where should I read to learn how to do this correctly???

emmm, I’m not sure how you learned golang, but this is a basic question. Basically all golang books mention the concept of slicing (it’s better to say this is basic knowledge).
Essentially, you directly “=” and just assign the underlying pointer. Both use the same pointer, so when either one is modified, the result will be the same.
When you copy, you actually create a slice of the same length and then assign it, and the pointers of the two are different.
Let’s take a look at the sample code to see what’s going on:

type v struct {
	a []int
	b []int
}

func main() {
	v1 := v{
		a: []int{1, 2, 3, 4},
		b: []int{5, 6, 7, 8},
	}
	fmt.Printf("v1 %p %p \n", v1.a, v1.b) //v1 0xc0000282c0 0xc0000282e0
	v2 := v1
	fmt.Printf("v2 %p %p \n", v2.a, v2.b) //v2 0xc0000282c0 0xc0000282e0
	v3 := v{a: make([]int, len(v1.a)), b: make([]int, len(v1.b))}
	copy(v3.a, v1.a)
	copy(v3.b, v1.b)
	fmt.Printf("v3 %p %p \n", v3.a, v3.b) //v3 0xc000028300 0xc000028320
	v1.a = append(v1.a, []int{9, 10, 11, 12, 13, 14, 15, 16}...)
	fmt.Printf("v1.a %p &v2.a %p \n", v1.a, v2.a) //v1.a 0xc00002a840 &v2.a 0xc0000282c0
}

If you do not understand the basic data structure, subsequent development will encounter various problems.

Yes I understand that about slices in main.go. I acknowledged that when I said at side question: “OK so I get it, in a structure with slices when copied with a
simple = or := the slices still point to the same memory locations.”

But if you go to PRIMARY Question I do not understand how if I call by VALUE a function using a slice or a structure with slices it can change the values in the calling code.

In summary it seems if I ever want to pass a slice or a struc with slices to a function I must make a copy and pass that!

I appreciate your response but my primary question remains “given this behavior how can Go be called a language that uses**
** CALL BY VALUE???**”

There is nothing difficult to understand, pass by value, what is passed is the value. When passing a pointer, the value of the pointer is passed, not the value pointed to by the pointer.
Let’s look at a sample code, I don’t want to say more:

func main() {
	l := []int{1, 2, 3, 4}
	t := 1
	fmt.Printf("1 l %p %p %p\n", l, &l, &t) //1 l 0xc0000282c0 0xc000012b40 0xc0000147a0
	handle(l, t)
	fmt.Printf("4 l %p %p %p\n", l, &l, &t) //4 l 0xc0000282c0 0xc000012b40 0xc0000147a0
}

func handle(l []int, t int) {
	fmt.Printf("2 l %p %p %p\n", l, &l, &t) //2 l 0xc0000282c0 0xc000012b70 0xc0000147a8
	l = append(l, []int{5, 6, 7, 8, 9}...)
	t = 2
	fmt.Printf("3 l %p %p %p\n", l, &l, &t) //3 l 0xc000024460 0xc000012b70 0xc0000147a8
}

Thank you I get that now - structures and slices are really pointers and it is the value of the pointer that is called.

BTW did you see Supplemental question - I pasted the code and output but as you can see it broke the listing up. Where should I read to learn how to do this correctly???

You can try markdown’s syntax. I don’t know if it is fully supported, but at least it is useful to write sample code.

Discourse (this forum software) supports Markdown. To format text as code, use three backticks before and after the code, like this:
```
<insert code here>
```

(Recommended) For syntax highlighting, specify the language after the first set of backticks, like this:
```go
func main() {}
```
which looks like this:

func main() {}
1 Like

Just to clarify: slices are pointers, as are maps and interfaces. But structs are not pointers. Structs are passed by value, copying all the fields in the struct, even if it’s huge. (Note that it’s rare for a golang struct to be huge, since it would have to have lots of fields or contain structs with lots of fields.)

In your case, you have structs in a slice. The slice is copied but it’s essentially a pointer, and the structs it contains end up being passed as though by reference.

1 Like

Thank You that clarification really helped. THANK YOU

So if the copied slice has structs copy(dst,src) will suffice UNLESS(???) the structs themselves have slices.

Assuming my UNLESS is valid then I would then have to copy the second order slices??

Can You recommend any of the deepcopy or clone functions I see libraries for (actually for which) online?

You can refer to the implementation of this, it is not difficult.

This implementation is good enough for my personal use.

1 Like