29

I am a bit confused about passing by reference and value in Go.

I've seen this explained of the * in front of a type.

* in front of a type name, means that the declared variable will store an address of another variable of that type (not a value of that type).

This just doesn't make sense to me.

In Java if I was passing a Database instance into a function I would do

 databaseFunction(DatabaseType db) {
      // do something
}

However in the go example I have it's passed like so.

func PutTasks(db *sql.DB) echo.HandlerFunc {

}

Why do we need to have the asterisk in front of the type?

According to this cheat sheet, I found.

func PrintPerson(p *Person) ONLY receives the pointer address (reference)

I don't understand why I would only want to send a pointer address as a parameter.

ruakh
  • 175,680
  • 26
  • 273
  • 307
N P
  • 2,319
  • 7
  • 32
  • 54

3 Answers3

66

First, Go technically has only pass-by-value. When passing a pointer to an object, you're passing a pointer by value, not passing an object by reference. The difference is subtle but occasionally relevant. For example, you can overwrite the pointer value which has no impact on the caller, as opposed to dereferencing it and overwriting the memory it points to.

// *int means you *must* pass a *int (pointer to int), NOT just an int!
func someFunc(x *int) {
    *x = 2 // Whatever variable caller passed in will now be 2
    y := 7
    x = &y // has no impact on the caller because we overwrote the pointer value!
}

As to your question "Why do we need to have the asterisk in front of the type?": The asterisk indicates that the value is of type pointer to sql.DB, rather than a value of type sql.DB. These are not interchangeable!

Why would you want to send a pointer address? So that you can share the value between the caller of a function and the function body, with changes made inside the function reflected in the caller (for example, a pointer is the only way that a "setter" method can work on an object). This is actually what your Java code is doing as well; in Java, you always access objects via references (pointers), so Java does this automatically instead of having you explicitly indicate it. But in Go you can also access an object not via a pointer, so you have to be explicit. If you call a function and pass in an object directly, the function will get a copy of that object, and if the function modifies that object, the caller won't see those changes. So if you want changes to propagate outside the function, you must pass a pointer. That way, the pointer will be copied, but the object that it points to will be shared.

See also: the Go tour section on Pointers, the Go spec section on pointers, the Go spec section on the address operators

ruakh
  • 175,680
  • 26
  • 273
  • 307
Adrian
  • 42,911
  • 6
  • 107
  • 99
  • 10
    Another reason pointers are passed is to reduce the size of the value being passed. A pointer is a single machine word (4 or 8 bytes, depending on your system architecture) in size. A sql.DB is a structure that it up to around 180 bytes in size. That's a lot of data to copy into a function call. – Kaedys Nov 14 '17 at 22:39
  • 5
    180b really isn't that much but yes, that is a valid reason in some cases to use pointers. In general I would not use that reasoning unless profiling indicated it solved a real problem. Premature optimization, root of all evil, yadda yadda. – Adrian Nov 14 '17 at 22:40
  • 5
    @Kaedys: 180 bytes is pretty insignificant. A single cache line is basically free, and most common CPUs transfer up to 8 lines in a single burst. Simply dereferencing a pointer may take much longer, or not, it depends on the data locality and cache state. I've optimized many pieces of code by removing pointers. Use a pointer for its functionality first and foremost. – JimB Nov 14 '17 at 23:53
  • 2
    I didn't mention memory savings in the answer because it sounds like a newer Go developer was asking, and it's easy for advice like that to lead to overuse or misuse of a feature. While there are certainly cases where it *might* help to save memory by passing a pointer, those cases are rare and should be found through direct measurement. For someone learning the language, I think it's better not to consider that a reason to use a pointer, and just focus on pointer semantics as the reason to use them. – Adrian Nov 15 '17 at 14:24
  • 10
    @Adrian Java also passes by value always – krulik Mar 11 '20 at 10:34
  • 6
    @krulik that's one way to look at it, but an unhelpful one for most developers. Since *all objects in Java are references*, any time you pass an object, you're *passing a reference*. Therefore, pass-by-reference semantics apply to the vast majority of Java code. – Adrian Mar 11 '20 at 12:42
  • 1
    @Adrian there's no difference between Java semantics and Go semantics in this case. You pass the reference by value in both languages. In both languages this value is stored in a new variable. – krulik Mar 12 '20 at 16:46
  • 1
    Since slices are always references, I think it becomes confusing to say that Go does not have references. You could say "the slice itself is a value", but that is not helpful, since if you assign a value of it, you're not manipulating a copy. Since there is no pointer syntax, it is also confusing to claim that a slice is "actually a pointer". – Janus Troelsen Oct 09 '20 at 16:42
  • 1
    Finally an answer which makes things easy to understand. I had the same question as OP (I come from C# background) – stack underflow Oct 12 '21 at 02:18
  • 1
    The java part is misleading. **Java is always pass by value**. – Yar Oct 13 '21 at 20:28
  • Java **never** passes by reference. Ever. Don't believe me? Write a function `foo` such that you can take a local variable`int x = 3`, then `foo(x); system.out.println(x)` would print something other than `3` – juanpa.arrivillaga Mar 16 '22 at 21:01
  • 3
    @juanpa.arrivillaga my answer says "While Java passes *objects* by reference". `int` is a primitive, not an object. All objects in Java are references. While technically references are passed by value, they're still references, which means the experience of Java developers is mostly passing references. Structs in Go are *not* references, even though they *look* like Java objects in some ways (having fields and methods). It is a useful comparison and distinction for developers used to Java-like languages. – Adrian Mar 17 '22 at 13:52
  • @Adrian but that is *not what call by reference means*. That is a common misunderstanding. Call by reference is not like passing a reference as value (for starters, that is a strange Javaism which actually describes *another* evaluation strategy, but for some reason, in the Java community, it is described as "call by value", but that's another topic).In call by reference, suppose you have a `List]` variable in the caller, and you do `foo(myList)`, and in the function, you do `paramter = anotherList`, the *assignment is seen in the caller, regardless of type*. That never works in Java – juanpa.arrivillaga Mar 17 '22 at 16:15
  • 3
    @juanpa.arrivillaga the only times the phrase "call by reference" appears on this page is in your comment, so I'm not sure what you're referring to. My point is as I explained previously: structs are values, unlike the objects devs coming from other languages might be used to, which are references. – Adrian Mar 17 '22 at 17:30
27

The purpose of reference semantics is to allow a function to manipulate data outside its own scope. Compare:

func BrokenSwap(a int, b int) {
  a, b = b, a
}

func RealSwap(a *int, b *int) {
  *a, *b = *b, *a
}

When you call BrokenSwap(x, y), there is no effect, because the function receives and manipulates a private copy of the data. By contrast, when you call RealSwap(&x, &y), you actually exchange the values of the caller's x and y. Taking the address of the variables explicitly at the call site informs the reader that those variables may be mutated.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

Pass by Reference :- When you pass a same variable into a function by different name.

Below example from C++ (as Go doesnt have this concept), where a and a1 are same variable.

void swap(int& a1, int& b1)
{
    int tmp = a1;
    a1 = b1;
    b1 = tmp;
}
 
int main()
{
    int a = 10, b = 20;
    swap(a, b);
    cout << "a " << a << " b " << b ;
}

Go passes everything as data( means it copies the data from current active frame to new active frame of new function). So if you pass values it copies the value and advantage is safety from accidental modification. And when it passes address of variable its copied also into the new pointer variables but has advantage of efficiency since size of pointer is smaller.

Sumer
  • 2,687
  • 24
  • 24