Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Technically no, but I get why it feels like this. :-)

I think the confusion stems from the fact that Go hides the distinction of "dot" access vs "pointer dot" access. (eg, the difference between `foo.Bar` and `foo->Bar` in C++). Go knows if an object is a pointer and needs to be de-referenced, and hides the de-reference operation from you syntactically. So you can use a pointer without knowing it's a pointer.

This is the confusion: You never have a "map object that is passed by reference", you instead have a "pointer to a map object that is always passed by value".

This is less confusing for structs the programmer defines themselves, since they can check the type of "foo" see if "foo.Boo" is accessing Bar directly or de-referencing "foo" and then accessing "Bar".

But it's more confusing when applied to builtin type for which you never see the implementation. How would you know if `map[string]bool{}` returns a value or a pointer? You don't!

The map type is passed by value but its implementation is that it is a thin wrapper around a pointer to a struct. Ergo in practice it feels like passing by reference. But Go is technically always pass by value. Map does not get any special implementation in the language.

You can do this yourself. `type MyStruct struct{ data *MyType }`. Now if you pass MyStruct by value, any operations on it are effectively by reference since all operations have to dereference `data` to get at the actual content.

(Same goes for strings, except they are immutable so no one notices.)

This might feel like semantics, but it's important to remember that Go doesn't treat any of those built-ins with special "pass by reference" rules. Instead, it's behaving consistently like it would for any types you defined yourself and one of the learning curves of the language is to think in Go's terms of pointers vs non-pointers and learn which native types are pointers. If you think of it that way, learning Go's built-ins is no different than learning the API methods for a custom struct Go's built-ins just happen to be, well, built-in and thus get syntactic sugar that your custom structs do not.

"Pass by reference" is usually used to refer to the case where you use a value at level N of the call stack, but the code at level N+1 of the callstack decides to make it a pointer. In Go this never happens, instead you technically always had a pointer the whole time!



From Google's Go project blog:

> Map types are reference types, like pointers or slices.

https://go.dev/blog/maps


Actually, here's an example of precisely why maps are not passed as references:

https://go.dev/play/p/-mEeg2Ud68V

This example cannot re-allocate the original map! If the map were truly passed by reference, it could be allocated in a local function. But it can't, only values within the map can be modified when a map is passed.

This is in contrast with pass by reference in, say, C++, in which case you can assign directly to and modify the reference. ex: https://www.ibm.com/docs/en/zos/2.4.0?topic=calls-pass-by-re...


Did you read my comment?

References are nothing special, they are are simply pointers that hide the pointer and usually the receiving definition makes the decision about whether a pointer of a copy is passed.

In Go the type is just a wrapper around a pointer, making it function like a reference in all cases.

In go some types are simply defined as pointers, so they are technically always passed by value and there is never any magic about whether they are passed by value or referenced. It is always a value consisting of a reference.

A map is a pointer that is passed by value, along with slices and channels. 100% of the time.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: