# 3. Pass by Reference

Functions in Go generally pass variables by value, meaning that functions receive a copy of most non-composite types:

{% code title="example.go" %}

```go
func increment(x int) {
    x++
    fmt.Println(x)
    // 6
}


func main() {
    x := 5
    increment(x)
    fmt.Println(x)
    // 5
}
```

{% endcode %}

The main function still prints 5 because the increment function received a copy of x.

One of the most common use cases for pointers in Go is to pass variables by reference, meaning that the function receives the address of the original variable, not a copy of the value. This allows the function to update the original variable's value.

{% code title="example\_pointer.go" %}

```go
func increment(x *int) {
    *x++
    fmt.Println(*x)
    // 6
}

func main() {
    x := 5
    increment(&x)
    fmt.Println(x)
    // 6
}
```

{% endcode %}

### Fields of Pointers

When your function receives a pointer to a struct, you might try to dereference and access a field like this and encounter an error:

```go
msgTotal := *analytics.MessagesTotal
```

Instead, access it — like you'd normally do — using a selector expression:

```go
msgTotal := analytics.MessagesTotal
```

This approach is the recommended, simplest way to access struct fields in Go, and is shorthand for:

```go
(*analytics).MessagesTotal
```

{% hint style="info" %}
Go automatically dereferences struct pointers when accessing fields, so prefer ptr.Field over (\*ptr).Field for readability.
{% endhint %}

### Pass by Value (Default)

When you pass a variable to a function, Go makes a copy:

{% code title="pass\_by\_value.go" %}

```go
func increment(x int) {
    x++  // Only changes the copy
    fmt.Println(x)  // 6
}

func main() {
    x := 5
    increment(x)  // Pass a copy of x
    fmt.Println(x)  // Still 5 (original unchanged)
}
```

{% endcode %}

What happens:

1. `x = 5` in main
2. `increment` receives a copy with value 5
3. The copy becomes 6
4. Original `x` in main is still 5

### Pass by Reference (Using Pointers)

When you pass a pointer, the function can modify the original:

{% code title="pass\_by\_reference.go" %}

```go
func increment(x *int) {
    *x++  // Changes the original
    fmt.Println(*x)  // 6
}

func main() {
    x := 5
    increment(&x)  // Pass address of x
    fmt.Println(x)  // 6 (original changed!)
}
```

{% endcode %}

What happens:

1. `x = 5` in main
2. `&x` gets the address of x
3. `increment` receives the address
4. `*x++` goes to that address and increments the value
5. Original `x` in main is now 6

### Visual Comparison

Pass by Value:

```
main:           function:
x = 5           x_copy = 5
  ↓               ↓
  5             x_copy++ → 6
  ↓               
  5 (unchanged)
```

Pass by Reference:

```
main:           function:
x = 5           x_ptr → points to x
  ↑               ↓
  6 ← ───────── *x_ptr++ (changes original)
```

### Real Example: Updating a User

Without pointer (doesn't work):

{% code title="update\_without\_pointer.go" %}

```go
func updateAge(u user, newAge int) {
    u.age = newAge  // Only changes the copy
}

type user struct {
    name string
    age  int
}

func main() {
    bob := user{name: "Bob", age: 25}
    updateAge(bob, 30)
    fmt.Println(bob.age)  // Still 25 (didn't change)
}
```

{% endcode %}

With pointer (works):

{% code title="update\_with\_pointer.go" %}

```go
func updateAge(u *user, newAge int) {
    u.age = newAge  // Changes the original
}

func main() {
    bob := user{name: "Bob", age: 25}
    updateAge(&bob, 30)
    fmt.Println(bob.age)  // 30 (changed!)
}
```

{% endcode %}

### Accessing Struct Fields Through Pointers

#### The Simple Way (Recommended)

```go
func updateAge(u *user, newAge int) {
    u.age = newAge  // Go automatically dereferences
}
```

#### What's Really Happening (Long Form)

```go
func updateAge(u *user, newAge int) {
    (*u).age = newAge  // Explicitly dereference then access field
}
```

Go lets you skip the `(*u)` and just write `u.age` as a convenience.

### Complete Example

{% code title="complete\_example.go" %}

```go
package main

import "fmt"

type user struct {
    name string
    age  int
}

// Pass by value - doesn't modify original
func tryToUpdateAge(u user, newAge int) {
    u.age = newAge
    fmt.Println("Inside function:", u.age)  // 30
}

// Pass by reference - modifies original
func actuallyUpdateAge(u *user, newAge int) {
    u.age = newAge
    fmt.Println("Inside function:", u.age)  // 30
}

func main() {
    bob := user{name: "Bob", age: 25}
    
    // Try without pointer
    tryToUpdateAge(bob, 30)
    fmt.Println("After tryToUpdateAge:", bob.age)  // Still 25
    
    // Try with pointer
    actuallyUpdateAge(&bob, 30)
    fmt.Println("After actuallyUpdateAge:", bob.age)  // Now 30
}
```

{% endcode %}

Output:

```
Inside function: 30
After tryToUpdateAge: 25
Inside function: 30
After actuallyUpdateAge: 30
```

### Accessing Multiple Fields

{% code title="update\_stats.go" %}

```go
type analytics struct {
    MessagesTotal int
    MessagesFailed int
}

func updateStats(a *analytics) {
    // Simple syntax (recommended)
    a.MessagesTotal++
    a.MessagesFailed += 5
    
    // Long form (what Go does behind the scenes)
    (*a).MessagesTotal++
    (*a).MessagesFailed += 5
}

func main() {
    stats := analytics{MessagesTotal: 100, MessagesFailed: 5}
    updateStats(&stats)
    fmt.Println(stats.MessagesTotal)  // 101
    fmt.Println(stats.MessagesFailed) // 10
}
```

{% endcode %}

### Common Mistake: Don't Double Dereference

```go
func updateStats(a *analytics) {
    // ❌ Wrong - don't dereference the pointer before accessing field
    total := *a.MessagesTotal  // ERROR: a.MessagesTotal is already an int
    
    // ✓ Correct - just access the field
    total := a.MessagesTotal
    
    // ✓ Also correct - explicitly dereference first
    total := (*a).MessagesTotal
}
```

{% hint style="warning" %}
When you have a pointer to a struct, don't try to dereference the field itself using \*a.Field — either use a.Field or (\*a).Field.
{% endhint %}

### When to Use Pointers in Functions

Use pointers when:

* You need to modify the original variable
* The variable is large (struct with many fields) and copying is expensive
* You want to avoid copying data

Don't use pointers when:

* The variable is small (int, bool, small string)
* You don't need to modify the original
* You want the function to be side-effect free

### Quick Reference

| Scenario                |                      Syntax | Result                       |
| ----------------------- | --------------------------: | ---------------------------- |
| Pass value              |   `func(x int)` → `func(5)` | Function gets copy           |
| Pass pointer            | `func(x *int)` → `func(&x)` | Function can modify original |
| Access field (simple)   |                 `ptr.field` | Recommended way              |
| Access field (explicit) |              `(*ptr).field` | Same, but verbose            |
| Modify through pointer  |              `*ptr = value` | Changes original             |

### Practice Exercise

{% code title="practice.go" %}

```go
type account struct {
    balance int
}

// Which of these will actually change the balance?

func deposit1(a account, amount int) {
    a.balance += amount
}

func deposit2(a *account, amount int) {
    a.balance += amount
}

func main() {
    acc := account{balance: 100}
    
    deposit1(acc, 50)
    fmt.Println(acc.balance)  // What prints? 100 (unchanged)
    
    deposit2(&acc, 50)
    fmt.Println(acc.balance)  // What prints? 150 (changed!)
}
```

{% endcode %}

Only deposit2 works because it receives a pointer and can modify the original.

### Assignment

Write an analyzeMessage function. It should accept a pointer to an Analytics struct and a Message struct (not a pointer).

It should look at the Success field of the Message struct and, based on that, increment the MessagesTotal, MessagesSucceeded, or MessagesFailed fields of the Analytics struct as appropriate.

```go
package main

type Analytics struct {
	MessagesTotal     int
	MessagesFailed    int
	MessagesSucceeded int
}

type Message struct {
	Recipient string
	Success   bool
}

// don't touch above this line

// ?
```

### Solution

{% code title="solution.go" %}

```go
package main

type Analytics struct {
	MessagesTotal     int
	MessagesFailed    int
	MessagesSucceeded int
}

type Message struct {
	Recipient string
	Success   bool
}

// don't touch above this line

func analyzeMessage(a *Analytics, m Message){
	if m.Success{
		a.MessagesSucceeded++
	}else{
		a.MessagesFailed++
	}
	a.MessagesTotal++
}
```

{% endcode %}

<details>

<summary>Why It Works</summary>

Function Signature

```go
func analyzeMessage(a *Analytics, m Message)
```

* `a *Analytics` - pointer to Analytics struct
  * Can modify the original struct
  * Changes persist after function returns
* `m Message` - value (copy) of Message struct
  * Just reading `Success` field
  * Don't need to modify, so no pointer needed

Accessing Fields

```go
a.MessagesSucceeded++  // Access pointer struct field (modifies original)
m.Success              // Access value struct field (reads copy)
```

* Go auto-dereferences pointers: `a.field` instead of `(*a).field`
* Both use dot notation, but pointer modifies original

Logic Flow

1. Check if message succeeded or failed
2. Increment appropriate counter (succeeded or failed)
3. Always increment total count

Calling the Function

```go
stats := Analytics{}
msg := Message{Success: true}
analyzeMessage(&stats, msg)  // Pass pointer to stats, value for msg
// stats is modified
```

Key Concepts

| Concept              | Syntax         | Purpose                              |
| -------------------- | -------------- | ------------------------------------ |
| Pointer parameter    | `a *Analytics` | Receive address, can modify original |
| Value parameter      | `m Message`    | Receive copy, read-only              |
| Access pointer field | `a.field`      | Modifies original struct             |
| Access value field   | `m.field`      | Reads from copy                      |
| Pass pointer         | `&stats`       | Send address of variable             |
| Pass value           | `msg`          | Send copy of variable                |

Why Use Pointer for Analytics?

* Need to modify the struct's fields
* Changes must persist after function returns
* Tracking stats requires updating the original

Why Use Value for Message?

* Only reading the `Success` field
* Don't need to modify the message
* Small struct, copying is cheap

</details>
