Will function hard copy?

If i have this function PrintBoard

func PrintBoard(board [3][3]byte) {
    // prints out the board
}

Will go create a new copy of my array before printing? Or will it recognize that no mutation are to be made and pass reference. Should i define the function like this instead?:

func PrintBoard(board *[3][3]byte) {
    // prints out the board
}

Arrays are values so that mean you can not change its contents in the function.
If you use an slice or a pointer to an array, that is a reference and you can change its contents

But will it allocate a completely new array to memory? Or will it pass a read-only reference? Should I pass a pointer even if the array will not be modified?

I think it is a matter of compiler optimization - if you pass an array by value, the compiler may decide to actually pass it by pointer (as long as you really don’t modify it in the function). But as with any optimization, it is not guaranteed to happen.

Write the code to match your intent, and only modify it for performance if it proves to be a bottleneck.

1 Like

The first version copies the slice header for board, but not the contents.
So mutating board is fine.
But if you change the dimensions of board, then your changes will be lost when the function exits.

1 Like

All explicit function parameters are passed by value, so your board's 9 bytes are copied (at least conceptually) into PrintBoard every time PrintBoard is called. That being said, it really depends on how complicated PrintBoard is and how it’s being called. If PrintBoard is just a few fmt.Printfs or other text formatting before writing to some io.Writer, for example, then PrintBoard will likely be inlined and could work with the board's bytes directly. If you do something like this, though:

var boardValueProc func([3][3]byte)

func main() {
    doSomething()
    var board [3][3]byte
    boardValueProc(board)
    // ...
}

func doSomething() {
    // ...
    boardValueProc = PrintBoard
    // ...
}

Then there is no way for the compiler to know (without some whole program analysis) that the function inside boardValueProc won’t modify the bytes in the board, so it will always be called with a copy of the values.

Since Go 1.16, the amd64 platform uses a new register-based internal ABI, so those 9 bytes are passed in registers (specifically the CX and BX registers; the 9th byte is zero-extended into the full 64-bit BX register), so the actual memory is no longer copied, but the values are.