
There is no pass by reference in Go - micah_chatt
https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
======
jasode
An extended explanation missing from Dave Cheney's answer is that the
"reference" etymology has at least 2 meanings. This is why his explanation is
virtually the same as the one 20 years ago in the C Language FAQ[1] compiled
by Steve Summit.

\- "reference" definition 1: an alias that cannot be null which is what a
"reference type" is in Pascal and C++. This might be thought of as a stricter
"computer-science" definition. The C and Go languages don't have this type of
"reference".

\- "reference" definition 2: a pointer variable that lets programmers change
the _" thing pointed to"_ instead of the pointer variable itself to avoid
copying unnecessary bytes. This is the colloquial usage. It also doesn't help
that we call the star operator the "de-REFERENCING" operator[2] instead of the
"de-POINTERIZING" operator. (What are we "derefencing" if it's not a
"reference"?!?)

Cheney is talking about definition 1.

[1] [http://www.di-srv.unisa.it/~vitsca/LAB/C-faq.html](http://www.di-
srv.unisa.it/~vitsca/LAB/C-faq.html) excerpt:

    
    
      4.11:	Does C even have "pass by reference"?
    
      A:	Not really.  Strictly speaking, C always uses pass by value.
    	You can simulate pass by reference yourself, by defining
    	functions which accept pointers and then using the & operator
    	when calling, and the compiler will essentially simulate it for
    	you when you pass an array to a function (by passing a pointer
    	instead, see question 6.4 et al.).  However, C has nothing truly
    	equivalent to formal pass by reference or C++ reference
    	parameters.  (On the other hand, function-like preprocessor
    	macros can provide a form of "pass by name".)
    

[2]
[https://en.wikipedia.org/wiki/Dereference_operator](https://en.wikipedia.org/wiki/Dereference_operator)

~~~
mannykannot
Indeed. Definition 2 is broadly in line with what "reference" means in general
usage, while definition 1 is a term of art in the vocabulary of certain
languages.

Before languages had reference types or pointers, the distinction between
pass-by-reference and pass-by-value (or also pass-by-name in Lisp and Algol)
told you important things about the semantics of the language, such as whether
a function you called could modify the objects you gave as arguments, or
incorporate them by reference into some other object, and how arguments that
are expressions are handled. Some of those distinctions become blurred when
pointers or references are passed by value; the distinction on _how_ you pass
them now becomes a distinction on _what_ you pass. In practice, is there any
language that passes pointers or references by reference?

~~~
lvh
It may be what reference means, but just because a language has references
doesn't mean that it is passing-by-reference. There are plenty of languages
that allow actual pass-by-ref, like C++. The usual litmus test is writing a
function that takes two ints (not int refs!) and they're swapped at the end.
In C++, you can tell because of "int&" in the signature of the function you're
calling; as opposed to plain int.

In languages with macros, you get to cheat a little, and write something that
looks like the above without _really_ having those semantics. However, in
languages like Lisps where your macro language is extremely powerful, you
might not really miss it so much.

There is a lot of convenience in _not_ having pass-by-ref! Sometimes I feel
like the ardent opposition just doesn't want to admit their favorite language
is missing a feature ;-) If I call a function f(a, b), I know that a, b are
still pointing at the same object in e.g. Python. That is not the case in C++
(pass-by-ref) or Lisp (arbitrary macros). Predictable language semantics make
code easier to reason about. That's a good thing, and it's quite plausible
that the added complexity and confusion of supporting pass-by-ref isn't worth
the expressiveness.

I appreciate that the term is confusing, but it does mean something. I submit
that making it mean two things would be even more confusing. If it's
confusing, just say "passing (an argument) _as a reference_" which is
unambiguously about what you're passing, and not how you're passing it.

~~~
Someone
_" If I call a function f(a, b), I know that a, b are still pointing at the
same object in e.g. Python."_

    
    
      def f(x):
        global a
        a = "No, you don't"
    
      a = "I know"
      f(a)
      print a
    

This counterexample may be far-sought, but it is a minimal version of what can
easily happen in larger programs that have shared mutable state.

But yes, call by reference can be confusing. It also can be very useful,
though. That's why many modern languages have call by reference, but also
require callers to specify it at each call site. I think that gives you the
best of both worlds.

------
pokstad
"Maps and channels are not references."

But then refer to the Go team's article on maps:

    
    
      Map types are reference types, like pointers or slices, and so the value of m above is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function:
      
      m = make(map[string]int)
      
      The make function allocates and initializes a hash map data structure and returns a map value that points to it. The specifics of that data structure are an implementation detail of the runtime and are not specified by the language itself. In this article we will focus on the use of maps, not their implementation.
    

Saying maps are not passed by reference is a bit deceiving. The map's
_pointer_ location is not passed by reference.

Source: [https://blog.golang.org/go-maps-in-
action](https://blog.golang.org/go-maps-in-action)

~~~
Rapzid
IMHO saying they are is misleading as this article correctly points out
nothing is, and Rob Pike himself has pointed out the same on many occasions.
They are referred to as "reference types" because they contain pointers to the
underlying data structure. However the thing stored in the variable is more
than just a pointer, and it is passed by value.

Knowing the difference can have important ramifications; particularly in the
case of a slice which has its header copied when passed to a function.

------
kstenerud
It's a question of semantics and the poorly chosen word "reference".

The roots come from C, where pretty much every book on the subject talked
about the difference between passing a huge, expensive value to a function vs
passing a cheap pointer "reference" to it.

And while the semantic purists will scream and holler, the fact remains that,
colloquially, a pointer is a reference to something, not the something itself.
And so this annoying debate rears its ugly head a few times a year and makes
it into HN or Slashdot or whatever.

~~~
lvh
Nobody is debating what the word "reference" means. The debate is that "pass-
by-reference" is already a different thing from passing something __as__ a
reference.

I appreciate that it's confusing to someone who isn't familiar with the term,
but so's most of CS. We had a term and it referred to a thing, and having it
refer to two different things is worse.

~~~
kstenerud
And yet this is the reality we live in. No matter how much talk of "should",
the reality stares you implacably in the face. This is a UX problem.

Practically speaking, the most important concept is that of cost, which the
naive answer covers. The distinction only matters in a language that actually
differentiates the two. Otherwise it's little more than trivia, and certainly
nothing to get worked up over.

~~~
ivanbakel
The difference between pass-as-reference and pass-by-reference is more than
trivia - if you were ignorant of it in a language, you might find trouble in
the future when a function decides to alter its argument values in a way that
negatively affects the caller. Part of the reason we should work to clarify
the language is to avoid misconceptions about behaviour based on what kind of
"reference" is meant.

~~~
tetromino_
A language with pointers also allows a function to alter its _logical_ (not
syntactical) argument values in a way that negatively affects the caller.

There isn't much practical difference between using

    
    
        // void c_func_alters_deref_pfoo(Foo * pfoo)
        Foo foo = { ... };
        c_func_alters_deref_pfoo(&foo);
    

and

    
    
        // void cpp_func_alters_foo(Foo & foo)
        Foo foo = { ... };
        cpp_func_alters_foo(foo);
    

besides the ability to pass null or otherwise invalid pointers in the C-style
version, which can (depending on situation) either simplify your API or be a
source of bugs.

~~~
ivanbakel
>A language with pointers also allows a function to alter its logical (not
syntactical) argument values

What's the difference between a logical and syntactical argument?

------
pebers
Minor nit...

> It is not possible to create a Go program where two variables share the same
> storage location in memory.

It is possible to do so, because the empty struct occupies no space. For
example:

    
    
        s := []struct{}{
            struct{}{},
            struct{}{},
        }
        fmt.Printf("%p %p\n", &s[0], &s[1])
    
        > 0x176f44 0x176f44
    

But that's kind of a fringe case, and I suppose one might argue that the two
variables occupy no space so in a sense they don't share that space. Either
way it doesn't detract from the original point of the post :)

------
kstenerud
Often, I'll deliberately give the naive "pointers are references" answer in a
job interview, just to gauge the interviewer's response.

It's actually a good proxy to determining company culture. If he starts to
patiently explain the difference, I'll stop him and talk about the practical
implications of the concept, and we'll have a good laugh.

If he gets annoyed or stiffens and things become tense, I'll have a good proxy
for what to expect should I make the mistake of working there.

~~~
mannykannot
Then there are those interviewers who silently cross you off the list and move
on. They are probably type II people, however, so no harm done from either
point of view.

------
brianolson
By this obtuse definition of 'pass by reference', Nothing with a C-like
function call stack will 'pass by reference'. Programming languages that
approximate 'pass by reference' will actually pass a pointer to the called
function that points to a value in the callee's stack frame. The pointer in
the called function is a local variable, so changing the value of that has no
effect in the callee's scope. Changing the contents of the thing pointed to is
the only _meaningful_ 'pass by reference', and practically most languages have
that. (including Go)

------
eliben
Interestingly, the term "reference type" has been removed from the Go spec in
2013:
[https://github.com/golang/go/commit/b34f0551387fcf043d65cd7d...](https://github.com/golang/go/commit/b34f0551387fcf043d65cd7d96a0214956578f94)

Yet some semi-official sources (like The Go Programming Language book) _do_
refer to channels as "reference types".

TBH, I find cheney's post not fully useful without explaining what _does_
happen behind the scenes in maps so that passing them by value doesn't incur
large copies.

~~~
iand
A map is a tiny struct containing a pointer to the bucket storage. It's always
cheap to pass a map value.

~~~
eliben
Right.

I'm saying the linked blog post can be improved significantly by spending a
paragraph on explaining this. Otherwise it just sounds like magic.

------
moomin
C# has a name for Go's object semantics: Marshal By Reference. This means that
when an object features in a call, the GC pointer aka reference is passed (by
value) rather than the object value itself. This reference is fundamentally
different from the reference concept in C++. So the term reference is
semantically overloaded and means different things in different programming
languages. However, the phrase "pass by reference" is language independent and
the author is correct, it doesn't have those semantics.

------
Myrmornis
When teaching, rather than using a special name like "pointer", wouldn't it be
better to simply explain that it's a variable that holds a memory address?
Once a student (e.g. who only knows a high-level language) understands that
they now have to think about memory explicitly, then the behavior of such a
variable will become obvious. AFAIU there are only two special features of
pointers: the dereference operation and the additive arithmetic which
increments in strides according to their type.

------
YZF
C++:

    
    
      void f(map<int, int> m)
      {
      	m[0] = 0;	
      }
    
      int main() {
      	map<int, int> t;
      	t[0] = 1;
      	f(t);
      	cout << t[0] << endl;
      	return 0;
      }
    

prints 1.

Go:

    
    
      func f(m map[int]int) {
      	m[0] = 0
      }
    
      func main(){
      	var t = make(map[int]int)
      	t[0] = 1
      	f(t)
      	fmt.Println(t[0])
      }
    

Prints 0.

So in C++ maps are passed by value. In Go they are passed by, hmm, "not
value".

Go could have made maps similar to C++ maps and then people could use a
pointer to a map when they wanted that. As it stands maps are "different"
which is not a big deal once you're used to it but still makes things a little
weird if you're coming from C++.

------
Animats
Go lacks the C++ reference operator. You can't write:

    
    
        func fn(m &map[int]int) {
            m = make(map[int]int)
        }
        ...
        fn(m)
    

You have to write:

    
    
        func fn(m *map[int]int) {
            *m = make(map[int]int)
        }
        ...
        fn(&m)
    

It's very C. The caller is forced to use different syntax to pass something as
a pointer/reference. In C++ and Rust, you can't see from the call whether
you're passing a pointer or a reference.

~~~
mastax
The difference is in C++ rvalues coerce to const&, while in Rust they do not.

E.x. this works

    
    
        int square(const int & num) {
            return num * num;
        }
        
        int main() {
            square(5);
        }
    

this does not

    
    
        fn takes_ref(a: &i32) -> i32 {
            *a
        }
    
        fn main() {
            takes_ref(64);
        }
    

There are still cases where you won't be able to tell if you're using a ref or
not, though:

    
    
        let x = returns_a_ref();
        takes_ref(x);

------
zackmorris
However, Go has pointers (just not pointer arithmetic):

[https://tour.golang.org/moretypes/1](https://tour.golang.org/moretypes/1)

Does anyone know of an imperative language doesn't have references, but also
doesn't have pointers? Perhaps using something like copy-on-write to pass
variables to functions.

------
maxpblum
I haven't used Go before; is there a common conception that you can pass by
reference in Go?

~~~
bsaul
I guess in every language with pointers, people often confuse passing the
pointer as a value with passing the object as a reference.

~~~
jbooth
I'm still confused and I've been working in various languages for 15 years.

If I pass a java object to a function, I'm passing a (probably) 8-byte pointer
to some memory with a class tag, fields, whatever. It goes on the stack just
like an 8 byte long.

In languages that support pointers more directly, I'm doing the same thing,
maybe minus the class tag in the pointed-to memory. Address is in an 8 byte
type, put it on the stack and access the pointed-to struct in your new frame.

Yet I've seen interview questions about whether you're "passing by reference"
or "passing a reference by value" like there's some big meaningful difference
and one answer is wrong.

I don't get it. Is this just one of those nerd arguments where we're debating
semantics for the sake of it?

~~~
lvh
In all of those cases, you're probably passing a reference by value,
semantically. ("Probably", because you didn't specify which languages, so I'm
making an educated guess.)

The usual litmus test is having two objects (or ints or whatever), write a fn
`swap(a, b)` where the two are swapped after the call is over. Can't do that
in Java or Go or Python or C; but you can in e.g. C++ and you sorta-can in
Lisp. In C++, you'd see int& (or whatever) show up in the arguments of swap().

~~~
jbooth
Ok, yeah, I saw upthread about C++ and Pascal having a more formal reference
type.

But in C and Go you can pass pointers to pointers, in Java and Python objects
with mutable object references..

It seems like the whole article could have been "Go does not have the C++
reference type, so it's not really in the mix when calling functions".

~~~
lvh
Yep. "Reference type" is a confused and overloaded term, so I prefer to say
"pass-by-reference" when I meant int& and "pass-as-reference" (or the, in my
opinion confused and confusing, pass-by-object, if that's helpful to the
listener).

------
htns
Doesn't the post stumble over right in the second section? "It is not possible
to create a Go program where two variables share the same storage location in
memory". So what? The C example didn't show that either.

~~~
lvh
You are correct that C also does not have pass-by-reference. However, the
second listing is a C++ program, not a C program, and C++ very much has pass-
by-reference. The C++ program demonstrates true aliases, as you can tell from
the output of the printf (see comment on same line).

~~~
htns
I have always found that is conflating the semantics of _using_ with the
method of _passing_. Even with/out aliases you are still _passing_ a
reference.

~~~
lvh
I don't think that's accurate. I can pass something locally declared as int to
a fn that takes int& according to it's signature. It seems that's precisely
what the confusion is about :)

