<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: mahdi</title>
    <description>The latest articles on Forem by mahdi (@mahdifardi).</description>
    <link>https://forem.com/mahdifardi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F113910%2F8447a9e2-baf9-45b0-8050-e427bedc750e.jpeg</url>
      <title>Forem: mahdi</title>
      <link>https://forem.com/mahdifardi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mahdifardi"/>
    <language>en</language>
    <item>
      <title>Why Is My nil Error Not nil in Go? Unpacking Nil Interfaces</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Thu, 24 Jul 2025 13:24:47 +0000</pubDate>
      <link>https://forem.com/mahdifardi/why-is-my-nil-error-not-nil-in-go-unpacking-nil-interfaces-j59</link>
      <guid>https://forem.com/mahdifardi/why-is-my-nil-error-not-nil-in-go-unpacking-nil-interfaces-j59</guid>
      <description>&lt;p&gt;If you've written Go for any amount of time, you've probably typed if err != nil hundreds of times. It’s the standard way to handle errors. But sometimes, this check behaves in a way that seems to defy logic, especially when you think you're returning a nil error. This "gotcha" moment almost always comes down to a misunderstanding of how Go's interfaces work, particularly when they are nil.&lt;/p&gt;

&lt;p&gt;Let's dive into what a nil interface really is and how to avoid this common pitfall.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an Interface, Really?
&lt;/h2&gt;

&lt;p&gt;First, it's crucial to understand that an interface variable isn't a simple value. It's a container with two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A type: This holds the type of the concrete data stored in the interface (e.g., *bytes.Buffer, *MyError).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A value: This holds the actual value or a pointer to the value (e.g., a pointer to a buffer, nil).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An interface variable is only truly nil when both of these parts are nil. This is the key to the whole mystery.&lt;/p&gt;

&lt;p&gt;Let's look at a simple example without even touching errors yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bytes"
    "fmt"
    "io"
)

func main() {
    // io.Reader is an interface.
    var r io.Reader
    fmt.Println(r == nil) // true

    // bytes.Buffer is a struct
    var b *bytes.Buffer
    fmt.Println(b == nil) // true

    r = b

    // r is now: (type=*bytes.Buffer, value=nil)
    fmt.Println(r == nil) // false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furaj4m04zzjmz1an43kj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furaj4m04zzjmz1an43kj.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we assign b to r, the interface r gets a type (*bytes.Buffer), so it's no longer considered nil, even though the value it holds is a nil pointer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common error Interface Pitfall
&lt;/h2&gt;

&lt;p&gt;This behavior becomes a real problem when dealing with the error interface. Many people think of error as a built-in primitive type, but it's not. It's an interface defined as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type error interface {
    Error() string
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any type that implements the Error() string method satisfies the error interface. Now, let's see how our new understanding of interfaces can lead to a bug.&lt;/p&gt;

&lt;p&gt;Imagine you have a custom error type and a function that might return it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

type MyError struct {
    Path string
    Msg  string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("%s: %s", e.Path, e.Msg)
}

func processFile(path string) *MyError {

    return nil
}

func main() {

    var err error = processFile("test.txt")


    if err != nil {
        fmt.Printf("Oops, an error occurred: %v\n", err) // This line will run!
        fmt.Printf("Type: %T, Value: %v\n", err, err)
    } else {
        fmt.Println("Everything is fine.")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this code produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Oops, an error occurred: &amp;lt;nil&amp;gt;
Type: *main.MyError, Value: &amp;lt;nil&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The err != nil check passes because the err variable, an error interface, was given a value (nil) that had a concrete type (*MyError). Since the interface's type part was set, the interface itself is no longer nil.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Return the Interface
&lt;/h2&gt;

&lt;p&gt;The fix is simple and is a cornerstone of good Go practice: functions should return the error interface type, not a concrete error type.&lt;/p&gt;

&lt;p&gt;By changing the function signature, you ensure that when you return nil, you're returning a true nil interface, where both the type and value are nil.&lt;/p&gt;

&lt;p&gt;Here’s the corrected code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

type MyError struct {
    Path string
    Msg  string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("%s: %s", e.Path, e.Msg)
}

func processFileCorrectly(path string) error {
    shouldFail := false 

    if shouldFail {
        return &amp;amp;MyError{Path: path, Msg: "file not found"}
    }


    return nil
}

func main() {
    err := processFileCorrectly("test.txt")

    if err != nil {
        fmt.Printf("Oops, an error occurred: %v\n", err)
    } else {
        fmt.Println("Everything is fine.") // This line runs now!
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;A nil pointer to a concrete type is not the same as a nil interface. An interface is only nil if both its internal type and value are nil.&lt;/p&gt;

&lt;p&gt;To avoid this trap, always make your functions that can fail return the error type. This way, when you return nil, you're creating a proper "zeroed" interface that will correctly evaluate to true in a == nil check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=AXCIEiebVfI&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=20" rel="noopener noreferrer"&gt;Go Class: 20 Interfaces &amp;amp; Methods in Detail&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.dev/tour/methods/12" rel="noopener noreferrer"&gt;Interface values with nil underlying values&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.dev/tour/methods/13" rel="noopener noreferrer"&gt;Nil interface values&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unpacking Go Slices: 3 Common Gotchas You Need to Know</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Thu, 17 Jul 2025 18:00:09 +0000</pubDate>
      <link>https://forem.com/mahdifardi/unpacking-go-slices-3-common-gotchas-you-need-to-know-mpa</link>
      <guid>https://forem.com/mahdifardi/unpacking-go-slices-3-common-gotchas-you-need-to-know-mpa</guid>
      <description>&lt;p&gt;Go's slices are a cornerstone of the language, offering a powerful and flexible way to work with sequences of data. However, their internal workings can lead to some surprising behavior if you're not careful. The common phrase "slices are passed by reference" is a helpful simplification, but it's not the whole story and can lead you into traps.&lt;/p&gt;

&lt;p&gt;Let's dive into three common "gotchas" that every Go developer should understand to write safer, more predictable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The append Pitfall: Slices are Passed by Value
&lt;/h2&gt;

&lt;p&gt;It’s a common misconception that passing a slice to a function allows the function to modify the original slice freely. Let's test this with an append operation.&lt;/p&gt;

&lt;p&gt;You might expect this code to print [string string2]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func update(s []string) {
    s = append(s, "string2") 
}

func main() {
    s := make([]string, 1, 1) 
    s[0] = "string"

    update(s)

    fmt.Println(s) // Output: [string]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Gotcha
&lt;/h3&gt;

&lt;p&gt;The output is [string], not [string string2]. Why?&lt;br&gt;
A slice isn't a direct pointer; it's a small descriptor object called a slice header. This header contains three fields:&lt;/p&gt;

&lt;p&gt;1- A pointer to an underlying array where the data is stored.&lt;/p&gt;

&lt;p&gt;2- The length of the slice.&lt;/p&gt;

&lt;p&gt;3- The capacity of the slice (the total size of the underlying array).&lt;/p&gt;

&lt;p&gt;When you pass a slice to a function, you are passing a copy of this header.&lt;/p&gt;

&lt;p&gt;In our update function, append sees that the slice's capacity is full (both length and capacity are 1). To add a new element, it must perform a reallocation: it creates a new, larger underlying array and copies the old elements over. The local copy of the slice header s inside update is modified to point to this new array, but the original slice header back in main remains unchanged and still points to the old, smaller array.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;To make the changes visible to the caller, you must return the (potentially new) slice from the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func update(s []string) []string {
    s = append(s, "string2")
    return s
}

func main() {
    s := make([]string, 1, 1)
    s[0] = "string"

    s = update(s) 

    fmt.Println(s) // Output: [string string2]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Takeaway:
&lt;/h3&gt;

&lt;p&gt;When a function modifies a slice's length or capacity (e.g., with append), it should always return the modified slice.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Stale Pointer: Risky Business with Element Addresses
&lt;/h2&gt;

&lt;p&gt;Taking a pointer to an element within a slice can be risky if the slice's length changes.&lt;/p&gt;

&lt;p&gt;Consider this example where we get a pointer to the first user, alice, and then append a new user to the slice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

type user struct {
    name  string
    count int
}

func addTo(u *user) {
    u.count++
}

func main() {
    users := []user{{"alice", 0}, {"bob", 0}} // Capacity is 2

    alice := &amp;amp;users[0]

    users = append(users, user{"amy", 0})

    addTo(alice)

    fmt.Println(users) // Output: [{alice 0} {bob 0} {amy 0}]
    fmt.Println(*alice) // Output: {alice 1}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Gotcha
&lt;/h3&gt;

&lt;p&gt;The final users slice shows Alice's count is still 0. The addTo(alice) call modified a version of "alice" that is no longer part of the slice!&lt;/p&gt;

&lt;p&gt;Just like in our first example, the append operation caused a reallocation. A new, larger array was created to hold alice, bob, and amy. The users slice variable was updated to point to this new array.&lt;/p&gt;

&lt;p&gt;However, our alice pointer is now a stale pointer—it still points to the memory location in the original backing array, which is no longer referenced by the users slice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaway
&lt;/h3&gt;

&lt;p&gt;Avoid holding pointers to slice elements if the slice might be reallocated by operations like append. It's often safer to work with indices.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The range Loop Trap: Capturing the Wrong Thing
&lt;/h2&gt;

&lt;p&gt;This is one of the most common gotchas for new Go programmers. When you use a for...range loop, Go uses a single variable to hold the value for each iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The `thing` variable is reused in each iteration.
for i, thing := range things {
    // thing is a copy of things[i]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reuse can cause chaos when you try to capture a slice or pointer from the iteration variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func main() {
    items := [][2]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
    a := [][]byte{}

    for _, item := range items {
        a = append(a, item[:])
    }

    fmt.Println("Original:", items)
    fmt.Println("Result:", a)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Output for a: [[1 2] [3 4] [5 6] [7 8]]&lt;br&gt;
Actual Output for a: [[7 8] [7 8] [7 8] [7 8]]&lt;/p&gt;
&lt;h3&gt;
  
  
  The Gotcha
&lt;/h3&gt;

&lt;p&gt;The item variable is a single [2]byte array in memory that gets overwritten on each loop. The expression item[:] creates a slice header that points to that memory. Each time we append, we are appending a slice that points to the same memory location. By the time the loop finishes, that memory holds the last value from items, which is {7, 8}. All the slices we appended into a now point to this final value.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;You must create a true copy of the data for each iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func main() {
    items := [][2]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
    a := [][]byte{}

    for _, item := range items {
        i := make([]byte, len(item))
        copy(i, item[:])
        a = append(a, i)
    }

    fmt.Println("Original:", items)
    fmt.Println("Result:", a)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Output for a: [[1 2] [3 4] [5 6] [7 8]]&lt;br&gt;
Actual Output for a: [[7 8] [7 8] [7 8] [7 8]]&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaway
&lt;/h3&gt;

&lt;p&gt;When creating slices or pointers from a range loop variable for later use, make sure you are capturing a fresh copy of the data, not a reference to the temporary loop variable itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/mahdifardi/go-slices-sharing-is-caring-until-you-run-out-of-room-34g4"&gt;Go Slices: Sharing is Caring, Until You Run Out of Room&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/mahdifardi/parameter-passing-in-golang-the-ultimate-truth-1h0o"&gt;Parameter Passing in Golang: The Ultimate Truth&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=904pyovPvXM&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=14" rel="noopener noreferrer"&gt;Go Class: 14 Reference &amp;amp; Value Semantics&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Unstable Address: A Deep Dive Into Why Go Maps Aren't Directly Modifiable</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Wed, 16 Jul 2025 12:53:22 +0000</pubDate>
      <link>https://forem.com/mahdifardi/the-unstable-address-a-deep-dive-into-why-go-maps-arent-directly-modifiable-1h96</link>
      <guid>https://forem.com/mahdifardi/the-unstable-address-a-deep-dive-into-why-go-maps-arent-directly-modifiable-1h96</guid>
      <description>&lt;p&gt;If you've spent any time with Go, you've almost certainly run into this famous compile error: cannot assign to struct field in map. It usually happens when you're trying to do something that feels completely natural.&lt;/p&gt;

&lt;p&gt;You have a map of structs, and you just want to change one little thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

type Book struct {
    Title string
    Pages int
}

func main() {
    library := make(map[string]Book)
    library["gopl"] = Book{Title: "The Go Programming Language", Pages: 380}


    library["gopl"].Pages = 400 //  Error: cannot assign to struct field in map
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error can be confusing. Why can't you do this? The answer reveals a core design philosophy of Go: a deep commitment to memory safety and predictability. Let's walk through the "why" and explore the right way to handle this situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mystery of the Moving Buckets
&lt;/h2&gt;

&lt;p&gt;The root of the issue lies in the nature of Go's maps. A map is a hash table, a dynamic data structure designed for fast lookups. To stay efficient, it needs to be able to grow.&lt;/p&gt;

&lt;p&gt;Think of a map as a magical, self-organizing filing cabinet. When you start adding too many files, the cabinet magically adds more drawers and rearranges the existing files to keep everything evenly distributed and easy to find.&lt;/p&gt;

&lt;p&gt;This "rearranging" is the key. When a Go map grows, it allocates a new, larger block of memory for its data (called buckets) and moves the existing elements from the old location to the new one.&lt;/p&gt;

&lt;p&gt;This means the memory address of a value you place inside a map is not stable. It could be in one place now, and a completely different place later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Golden Rule: Addressability
&lt;/h2&gt;

&lt;p&gt;This brings us to Go's golden rule for memory safety: you can only get a pointer to something that has a stable memory location. This "something" is called an addressable value.&lt;/p&gt;

&lt;p&gt;Because map elements can move at any time, they are not addressable.&lt;/p&gt;

&lt;p&gt;The Go compiler forbids you from taking the address of a map element (&amp;amp;myMap["key"]) to prevent a catastrophic bug: creating a dangling pointer. A dangling pointer is a pointer that points to a memory location that no longer holds the data you expect, leading to unpredictable crashes and data corruption.&lt;/p&gt;

&lt;p&gt;The error &lt;em&gt;cannot assign to struct field&lt;/em&gt; is the compiler's way of enforcing this rule. Modifying a field (.Pages = 400) requires getting a temporary pointer to the struct, and since the struct is in a map, that's not allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing The Two Kinds of Maps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Map of Values (The Problematic Case)
&lt;em&gt;map[string]Book&lt;/em&gt;
In this map, the Book structs live directly inside the map's buckets. When the map rearranges its buckets, the data itself moves.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wcskfmay4zwu45ebyoa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wcskfmay4zwu45ebyoa.jpg" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map of Pointers (The Idiomatic Solution)
&lt;em&gt;map[string]*Book&lt;/em&gt;
Here, the map's buckets only contain pointers. The actual Book structs live elsewhere in a stable location (the heap). When the map rearranges, it only moves the pointers. The data itself stays put.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfjocxhrzm3iwwm4joy1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfjocxhrzm3iwwm4joy1.jpg" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;br&gt;
Because the data's address is stable, you can safely modify it through the pointer.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Ultimate Proof: Peeking Under the Hood
&lt;/h2&gt;

&lt;p&gt;For those who want to see this rearrangement happen with their own eyes, we can use Go's unsafe package to peek directly at the memory addresses the map uses.&lt;/p&gt;

&lt;p&gt;Warning: This code is for demonstration only. Using the unsafe package breaks Go's safety guarantees and should be avoided in production code.&lt;/p&gt;

&lt;p&gt;This program prints the memory address of a map's internal "bucket array" before and after forcing it to grow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

type Book struct {
    Index int
    Pages int
}


type hmap struct {
    count     int
    flags     uint8
    B         uint8
    noverflow uint16
    hash0     uint32
    buckets   unsafe.Pointer 
}

func bucketArrayPtr(m interface{}) unsafe.Pointer {
    h := (*hmap)(unsafe.Pointer(reflect.ValueOf(m).Pointer()))
    return h.buckets
}

func main() {
    vm := make(map[int]Book)
    vm[1] = Book{Index: 1}
    fmt.Printf("Value-map buckets @ %p\n", bucketArrayPtr(vm))

    // Force a grow
    for i := 2; i &amp;lt;= 500; i++ {
        vm[i] = Book{Index: i}
    }
    fmt.Printf("Value-map buckets @ %p (after grow)\n\n", bucketArrayPtr(vm))

    pm := make(map[int]*Book)
    pm[1] = &amp;amp;Book{Index: 1}
    heapAddr := pm[1] 

    fmt.Printf("Pointer-map buckets @ %p, Book #1 @ %p\n", bucketArrayPtr(pm), heapAddr)

    // Force a grow
    for i := 2; i &amp;lt;= 500; i++ {
        pm[i] = &amp;amp;Book{Index: i}
    }
    fmt.Printf("Pointer-map buckets @ %p (after grow), Book #1 @ %p\n", bucketArrayPtr(pm), pm[1])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Output and What It Means&lt;br&gt;
When you run this, you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value-map buckets @ 0xc00010c000
value-map buckets @ 0xc00012a000 (after grow)

pointer-map buckets @ 0xc000138000, Book#1 @ 0xc00000a0f0
pointer-map buckets @ 0xc000150000 (after grow), Book#1 @ 0xc00000a0f0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1- Value-Map: The bucket address changed. This is definitive proof that the data stored inside the map moved.&lt;/p&gt;

&lt;p&gt;2- Pointer-Map: The bucket address changed, but the address of Book #1 on the heap stayed exactly the same.&lt;/p&gt;

&lt;p&gt;This code provides concrete evidence of our theory. The map's internal storage is unstable, but the data you point to from within it can be perfectly stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solutions: Two Ways Forward
&lt;/h2&gt;

&lt;p&gt;So, how do you fix the original code?&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 1: The "Copy-Modify-Replace" Pattern
&lt;/h3&gt;

&lt;p&gt;If you must use a map of values, you have to follow this three-step dance:&lt;/p&gt;

&lt;p&gt;1- Copy the struct out of the map into a temporary variable.&lt;/p&gt;

&lt;p&gt;2- Modify the temporary variable.&lt;/p&gt;

&lt;p&gt;3- Replace the value in the map with your modified copy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;library := make(map[string]Book)
library["gopl"] = Book{Title: "The Go Programming Language", Pages: 380}

tmp := library["gopl"]   // 1. Copy
tmp.Pages = 400          // 2. Modify
library["gopl"] = tmp    // 3. Replace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but it's verbose and can be inefficient if the struct is large.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 2: The Go Way - Use Pointers
&lt;/h3&gt;

&lt;p&gt;The more common and idiomatic solution is to simply store pointers in your map from the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;library := make(map[string]*Book)
library["gopl"] = &amp;amp;Book{Title: "The Go Programming Language", Pages: 380}

library["gopl"].Pages = 400 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is cleaner, more efficient, and communicates your intent to modify the values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: A Feature, Not a Bug
&lt;/h2&gt;

&lt;p&gt;The inability to directly modify a value in a map isn't a flaw in Go; it's a deliberate design decision. A look at the Go team's internal discussions (like GitHub &lt;a href="https://github.com/golang/go/issues/3117" rel="noopener noreferrer"&gt;Issue #3117&lt;/a&gt;) shows they chose predictability and memory safety over a minor syntactic convenience.&lt;/p&gt;

&lt;p&gt;So the next time you encounter this error, don't see it as a limitation. See it as Go protecting you from a whole class of subtle, dangerous bugs. It's a reminder to be explicit about your data, leading to code that is safer, clearer, and easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/golang/go/issues/3117" rel="noopener noreferrer"&gt;Issue #3117&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://utcc.utoronto.ca/~cks/space/blog/programming/GoAddressableValues" rel="noopener noreferrer"&gt;Addressable values in Go (and unaddressable ones too)&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=0m6iFd9N_CY&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=13&amp;amp;t=893s" rel="noopener noreferrer"&gt;Go Class: 12 Structs, Struct tags &amp;amp; JSON&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Go Slices: Sharing is Caring, Until You Run Out of Room</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Tue, 15 Jul 2025 15:48:34 +0000</pubDate>
      <link>https://forem.com/mahdifardi/go-slices-sharing-is-caring-until-you-run-out-of-room-34g4</link>
      <guid>https://forem.com/mahdifardi/go-slices-sharing-is-caring-until-you-run-out-of-room-34g4</guid>
      <description>&lt;p&gt;In this post, we will demonstrate the relationship between a slice and its underlying array. To explain this concept, we'll use a code example and walk through it step-by-step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    var a [3]int = [3]int{1, 2, 3}
    b := a[0:1]
    c := a[0:2]

    b = append(b, 4)                 // grows b, mutates a
    fmt.Printf("a[%p]= %v\n", &amp;amp;a, a) // a[0xc0000121f8]= [1, 4, 3]
    fmt.Printf("b[%p]= %[1]v\n", b)  // b[0xc0000121f8]= [1, 4]

    c = append(c, 5)                 // grows c, mutates a
    fmt.Printf("a[%p]= %v\n", &amp;amp;a, a) // a[0xc0000121f8]= [1, 4, 5]
    fmt.Printf("c[%p]= %[1]v\n", c)  // c[0xc0000121f8]= [1, 4, 5]

    c = append(c, 6)                 // because cap c is 3, this operation forces to reallocate c with doubling cap
    fmt.Printf("a[%p]= %v\n", &amp;amp;a, a) // a[0xc0000121f8]= [1, 4, 5]
    fmt.Printf("c[%p]= %[1]v\n", c)  // c[0xc0000145d0]= [1, 4, 5, 6]
    fmt.Println("cap c: ", cap(c))   // cap c: 6

    c[0] = 9                         // mutates a different array!
    fmt.Printf("a[%p]= %v\n", &amp;amp;a, a) // a[0xc0000121f8]= [1, 4, 5]
    fmt.Printf("c[%p]= %[1]v\n", c)  // c[0xc0000145d0]= [9, 4, 5, 6]

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1-initialization:
&lt;/h2&gt;

&lt;p&gt;So when we define a, b and c we some something like this image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyby6vr3f9y5epod844kc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyby6vr3f9y5epod844kc.jpg" alt=" " width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see a is an array and b, c is slices that a is their underlying array.&lt;/p&gt;

&lt;h2&gt;
  
  
  2- b = append(b, 4)
&lt;/h2&gt;

&lt;p&gt;•  b has a length of 1 and a capacity of 3. There is room to add elements.&lt;br&gt;
•  No reallocation is needed. The append operation adds the value 4 into the next available spot in the underlying array a.&lt;br&gt;
•  This overwrites a[1].&lt;br&gt;
•  a is mutated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuqx60iv0yvcu61lacv5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuqx60iv0yvcu61lacv5.jpg" alt=" " width="800" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3- c = append(c, 5)
&lt;/h2&gt;

&lt;p&gt;•  c has a length of 2 and a capacity of 3. There is still room.&lt;br&gt;
•  No reallocation is needed. The append adds 5 into the next spot in the underlying array a.&lt;br&gt;
•  This overwrites a[2].&lt;br&gt;
•  a is mutated again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo68pfilj2c8uslbka58r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo68pfilj2c8uslbka58r.jpg" alt=" " width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4- c = append(c, 6)
&lt;/h2&gt;

&lt;p&gt;•  c now has a length of 3 and a capacity of 3. There is no more room.&lt;br&gt;
•  To add 6, append must perform a reallocation.&lt;br&gt;
•  It creates a new, larger array (with a new capacity, typically doubled to 6), copies the elements [1, 4, 5] over, and then appends 6.&lt;br&gt;
•  The slice c is updated to point to this new array. It no longer shares data with a.&lt;br&gt;
•  a is not affected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zmo4lbwypp4olldnsb9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zmo4lbwypp4olldnsb9.jpg" alt=" " width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5- c[0] = 9
&lt;/h2&gt;

&lt;p&gt;•  This modifies the first element of the slice c.&lt;br&gt;
•  Since c now points to its own separate, underlying array, this change only affects c.&lt;br&gt;
•  a remains completely untouched.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcecd6p3xwps9cv5x529d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcecd6p3xwps9cv5x529d.jpg" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  code output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a[0xc0000121f8]= [1 4 3]
b[0xc0000121f8]= [1 4]
a[0xc0000121f8]= [1 4 5]
c[0xc0000121f8]= [1 4 5]
a[0xc0000121f8]= [1 4 5]
c[0xc0000145d0]= [1 4 5 6]
cap c:  6
a[0xc0000121f8]= [1 4 5]
c[0xc0000145d0]= [9 4 5 6]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The memory addresses shown in the output (like 0xc0000121f8) are specific to a single execution of the program. When you run the code on your machine, the operating system will allocate memory at different addresses.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=pHl9r3B2DFI&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=11" rel="noopener noreferrer"&gt;Go Class: 10 Slices in Detail&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Practical Guide to Defer, Panic, and Recover in Go</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Mon, 14 Jul 2025 21:11:31 +0000</pubDate>
      <link>https://forem.com/mahdifardi/a-practical-guide-to-defer-panic-and-recover-in-go-3bd7</link>
      <guid>https://forem.com/mahdifardi/a-practical-guide-to-defer-panic-and-recover-in-go-3bd7</guid>
      <description>&lt;p&gt;How do we guarantee that a cleanup task, like closing a file or unlocking a mutex, always gets done in our Go programs? This is a critical question for writing robust and reliable software. Fortunately, Go provides a powerful and elegant set of tools for this: the defer, panic, and recover keywords.&lt;br&gt;
Let's dive into how to use them effectively.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Magic of defer
&lt;/h2&gt;

&lt;p&gt;The defer statement schedules a function call to be executed just before the function it's in returns. It's the simplest way to guarantee that something happens, no matter how the function exits.&lt;/p&gt;

&lt;p&gt;Common use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Closing a file handle&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Closing a network connection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unlocking a mutex&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a classic example of using defer to ensure a file is closed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    f, err := os.Open("my_file.txt")
    // IMPORTANT: Always check for the error before deferring!
    // If os.Open fails, 'f' will be nil, and calling f.Close() would cause a panic.
    if err != nil {
        log.Fatal(err)
    }
    // This call to f.Close() is now guaranteed to run when main() exits.
    defer f.Close()

    // ... and now we can do something with the file ...
    fmt.Println("File opened successfully. Deferring the close.")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A key thing to remember is that defer is function-scoped, not block-scoped. It doesn't matter if the defer is inside an if block or a for loop; the deferred call will only execute when the entire function returns. This can lead to a common gotcha.&lt;/p&gt;

&lt;p&gt;The defer in a Loop Gotcha&lt;br&gt;
Consider opening multiple files in a loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Warning: This code has a potential bug!
func processFiles(filenames []string) {
    for _, filename := range filenames {
        f, err := os.Open(filename)
        if err != nil {
            log.Printf("failed to open %s: %v", filename, err)
            continue
        }

        // This will NOT close the file at the end of the loop iteration.
        // It will wait until processFiles() returns.
        defer f.Close()

        // ... do work with f ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, the f.Close() calls are all queued up and will only run when the processFiles function finishes. If you're processing a large number of files, you could easily run out of available file descriptors, crashing your program.&lt;/p&gt;

&lt;p&gt;The solution is to either call Close() explicitly at the end of the loop or refactor the loop's body into its own function, where defer can work as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Panic! And the Unwinding Stack
&lt;/h2&gt;

&lt;p&gt;A panic is a built-in function that stops the ordinary flow of control. It's typically used to signal a truly unexpected and unrecoverable error.&lt;/p&gt;

&lt;p&gt;When a function panics, its execution stops immediately. However, any deferred functions are still executed before the program unwinds the call stack. Deferred calls are executed in &lt;strong&gt;LIFO (Last-In, First-Out) order&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's see this in action with a recursive function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func main() {
    f()
    fmt.Println("Returned normally from f.")
}

func f() {
    fmt.Println("Calling g.")
    g(0)
    // This line is never reached because g panics.
    fmt.Println("Returned normally from g.")
}

func g(i int) {
    if i &amp;gt; 3 {
        fmt.Println("Panicking!")
        panic(fmt.Sprintf("%v", i)) // Panic when i is 4
    }
    // This defer is pushed onto the stack for each call to g.
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run this, the flow is:&lt;/p&gt;

&lt;p&gt;1- main calls f.&lt;/p&gt;

&lt;p&gt;2- f calls g(0), which calls g(1), then g(2), then g(3).&lt;/p&gt;

&lt;p&gt;3- Each call to g prints "Printing in g..." and defers its "Defer in g..." message.&lt;/p&gt;

&lt;p&gt;4- g(3) calls g(4), which triggers the panic.&lt;/p&gt;

&lt;p&gt;5- The panic stops normal execution and starts unwinding the stack.&lt;/p&gt;

&lt;p&gt;6- As each g function call exits due to the panic, its deferred fmt.Println is executed in LIFO order.&lt;/p&gt;

&lt;p&gt;The output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
panic: 4

goroutine 1 [running]:
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the deferred statements ran in reverse order (3, 2, 1, 0) after the panic started.&lt;/p&gt;

&lt;h2&gt;
  
  
  recover: Taming the Panic
&lt;/h2&gt;

&lt;p&gt;What if we want to catch a panic and handle it gracefully instead of letting it crash our program? This is where recover comes in.&lt;/p&gt;

&lt;p&gt;recover is a built-in function that regains control of a panicking goroutine. The golden rule is that recover is only useful when called directly inside a deferred function.&lt;/p&gt;

&lt;p&gt;Let's modify our previous example to recover from the panic in function f:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func main() {
    f()
    // Because we recovered, the program now finishes normally.
    fmt.Println("Returned normally from f.")
}

func f() {
    // Defer a function that will run when f exits.
    defer func() {
        // recover() checks if the program is panicking.
        if r := recover(); r != nil {
            // It catches the value passed to panic() and stops the panic.
            fmt.Println("Recovered in f:", r)
        }
    }()

    fmt.Println("Calling g.")
    g(0) // This call will panic.
    // This line is still never reached.
    fmt.Println("Returned normally from g.")
}

// g() function is the same as before
func g(i int) {
    if i &amp;gt; 3 {
        fmt.Println("Panicking!")
        panic(fmt.Sprintf("%v", i))
    }
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the program's flow changes:&lt;/p&gt;

&lt;p&gt;1- The execution proceeds as before, ending with a panic in g(4).&lt;/p&gt;

&lt;p&gt;2- The stack unwinds, and the deferred calls in g are executed.&lt;/p&gt;

&lt;p&gt;3- The panic propagates up to f.&lt;/p&gt;

&lt;p&gt;4- Before f exits, its deferred function is executed.&lt;/p&gt;

&lt;p&gt;5- Inside that deferred function, recover() catches the panic value ("4"), stops the panicking sequence, and allows f to return normally.&lt;/p&gt;

&lt;p&gt;6- Execution continues in main, which now prints its final line.&lt;/p&gt;

&lt;p&gt;The new output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
Recovered in f: 4
Returned normally from f.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the program no longer crashes.&lt;/p&gt;

&lt;p&gt;While recover is powerful, it should be used carefully. A good use case is in a web server, where you might want to recover from a panic in a single HTTP request handler without crashing the entire server. In most cases, however, it's better to use Go's standard error values for error handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summery
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use defer for cleanups that must run at function exit (closing files, unlocking mutexes).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid deferring inside tight loops—it defers until function exit, not loop exit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check errors first, then defer the cleanup.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resouces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://go.dev/blog/defer-panic-and-recover" rel="noopener noreferrer"&gt;https://go.dev/blog/defer-panic-and-recover&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=wj0hUjRHkPs&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=9" rel="noopener noreferrer"&gt;Go Class: 08 Functions, Parameters &amp;amp; Defer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.packtpub.com/en-us/product/mastering-go-9781805122647" rel="noopener noreferrer"&gt;Mastering Go: Leverage Go's expertise for advanced utilities, empowering you to develop professional software , Fourth Edition&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>godev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Parameter Passing in Golang: The Ultimate Truth</title>
      <dc:creator>mahdi</dc:creator>
      <pubDate>Thu, 10 Jul 2025 00:02:54 +0000</pubDate>
      <link>https://forem.com/mahdifardi/parameter-passing-in-golang-the-ultimate-truth-1h0o</link>
      <guid>https://forem.com/mahdifardi/parameter-passing-in-golang-the-ultimate-truth-1h0o</guid>
      <description>&lt;p&gt;We often learn that Go parameters are either passed by value or by reference. For example, basic types (ints, bools, etc.), arrays and structs are “by value,” while things like pointers, slices, maps, and channels are often called “by reference.” In practice this terminology can be misleading. In Go, every function parameter is passed by value (i.e. copied). That copy might be a simple value (for an int or an array) or a more complex descriptor (for a slice, string, or map).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Passed by value: numbers, booleans, arrays, structs, etc. (the entire value is copied)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reference-like types: pointers, strings, slices, maps, channels (the pointer or descriptor is copied)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s walk through some examples to see what really happens.&lt;/p&gt;

&lt;p&gt;Passing an Array (By Value)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func do(b [3]int) int {
    b[0] = 0
    return b[1]
}

func main() {
    a := [3]int{1, 2, 3}
    v := do(a)
    fmt.Println(a, v)  // [1 2 3] 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, do takes a fixed-size array b [3]int. When we call do(a), Go makes a copy of a and passes it to do. Inside do, setting b[0] = 0 only affects the copied array, not the original. This is why after calling do, the original a is still [1 2 3]. As the Go blog explains, “when you assign or pass around an array value you will make a copy of its contents.” (If you want to modify the caller’s array, you’d have to pass a pointer to the array, e.g. * [3]int.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing a Map (Pointer-Like Behavior)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func do(m1 map[int]int) {
    m1[3] = 1
    m1[4] = 3
}

func main() {
    m := map[int]int{4: 2}
    fmt.Println(m)  // map[4:2]
    do(m)
    fmt.Println(m)  // map[3:1 4:3]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, do takes a map. Internally, a Go map is implemented as a pointer to a runtime hash table structure. When we call do(m), Go copies the map descriptor (which is effectively a pointer) and passes it to do. The code m1[3] = 1 then mutates the underlying hash table. Because the descriptor copy still points to the same map data, the original map m in main sees the changes. In other words, the argument m and the parameter m1 both refer to the same map in memory. As Alex Edwards notes, Go “implements a map as a pointer to a runtime.hmap struct,” so passing a map to a function gives you a copy of that pointer – modifying the map will mutate the original data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Slice Puzzle: Append and Capacity
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func do(b []int) int {
    b = append(b, 4)
    b[0] = 0
    return b[1]
}

func main() {
    a1 := []int{1, 2, 3}
    fmt.Printf("len %d cap %d\n", len(a1), cap(a1))  // len 3 cap 3
    v1 := do(a1)
    fmt.Println(a1, v1)  // [1 2 3] 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many people expect slices to behave like maps in the previous example (with changes showing up outside). But here, after calling do(a1), the slice a1 is still [1 2 3]. What happened? Remember that a slice value in Go is itself a 3-word descriptor: it contains a pointer to an underlying array, a length, and a capacity. In our example, a1 := []int{1,2,3} has length 3 and capacity 3. Inside do, we do b = append(b, 4). Since the capacity of b was only 3, append allocates a new underlying array (with larger capacity), copies the old elements over, and returns a new slice header with that new array pointer. Then b[0] = 0 writes to this new array. Meanwhile, the original slice a1 in main still points to the old array (which was untouched). In short, the append caused a reallocation, so b inside do ended up pointing to a different array than a1 does. The assignment b[0] = 0 did not affect a1’s data. As Alex Edwards explains, the slice returned by append “may or may not point to the same underlying array” depending on capacity. If it allocates a new array, the function’s copy of the slice header is changed without affecting the caller’s slice. This is why a1 remains [1 2 3] even though do returned 0 at index 1 of its (new) slice.&lt;br&gt;
All Parameters Are Passed By Value&lt;br&gt;
The key insight is: Go always copies the function arguments. The phrase “pass-by-value” means every argument is copied. There is no hidden “pass-by-reference” semantics in Go. Even when we passed a pointer, a slice, or a map, the pointer or descriptor was copied by value. As Alex Edwards emphasizes, “parameters are always a copy of the arguments. That is, they are always passed by value.”.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In other words, a function parameter is never an alias for the caller’s variable. The only way a function can change the caller’s variable is if the caller passes in something like a pointer and the function dereferences it to write through to the original data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Descriptors for Strings, Slices, and Maps
&lt;/h2&gt;

&lt;p&gt;In Go’s runtime, complex types like strings, slices, and maps are built on small header (descriptor) values that contain pointers under the hood. For example, a Go string is a two-word struct: a pointer to the UTF-8 data and a length. A slice is a three-word struct: a pointer to the first element of an array, the slice length, and the slice capacity. A map is not described by just a few words in Go code, but internally it’s a pointer to a runtime hash table. Thus, when you pass a map or channel to a function, you are copying that pointer-like header. Any element writes (like m1[3]=...) update the shared data. Notice that in each case, what gets copied is the header or pointer, not the entire contents. So when we say slices or maps are “reference types,” we mean their headers contain pointers to shared data. But the headers themselves are passed by value (copied) into functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing a Pointer to a Slice
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func do(b *[]int) int {
    *b = append(*b, 4)
    (*b)[0] = 0
    return (*b)[1]
}

func main() {
    a1 := []int{1, 2, 3}
    fmt.Printf("len %d cap %d\n", len(a1), cap(a1))  // len 3 cap 3
    v1 := do(&amp;amp;a1)
    fmt.Println(a1, v1)  // [0 2 3 4] 2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we really want the function to be able to grow the caller’s slice? Here do takes a pointer to a slice (*[]int). Now, inside do we do *b = append(*b, 4) – this dereferences the pointer and reassigns the caller’s slice variable to the new slice value returned by append. Then (*b)[0] = 0 writes to the shared array. When we run this, the output shows a1 has become [0 2 3 4]. By passing &amp;amp;a1, we gave do the address of the slice header. Any assignment to *b actually updates a1 in main. As the official blog notes, writing *s = append(*s, …) will be “written-through to the memory address of the scores argument”. In other words, using a pointer-to-slice parameter forces append and other reassignments to affect the original slice variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go always passes function arguments by value. Even a pointer, slice, map or channel parameter is still a copy of whatever header or pointer you passed in. There is no hidden pass-by-reference mechanism.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic types, arrays, structs: Passing them copies the entire value. Mutating the parameter never changes the caller’s variable unless you passed a pointer to it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Slices, maps, channels: Each has an internal header (pointer + length/capacity or pointer to a hash table). Passing one of these copies the header. Mutations to the underlying data (e.g. setting a slice element or a map entry) affect the original data structure. However, reassigning the slice or map (like b = append(b,…) or m = make(map…)) only changes the local copy of the header, not the caller’s copy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strings: Immutable, but a string header (pointer + length) is also passed by value. Slicing a string creates a new header pointing into the same data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, don’t think in terms of “Go passes this by reference.” Think of it as “Go copies values,” and the effect depends on what those values are. If the value contains a pointer to shared data (as in slices or maps), then functions can mutate that shared data. If you need a function to update a variable itself (like extend a slice or change a struct), you must pass a pointer to it. This understanding will help avoid confusing surprises and make your Go code behavior predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=nxWqANttAdA&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=5" rel="noopener noreferrer"&gt;Go Class: 04 Strings&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=wj0hUjRHkPs&amp;amp;list=PLoILbKo9rG3skRCj37Kn5Zj803hhiuRK6&amp;amp;index=9&amp;amp;t=9s" rel="noopener noreferrer"&gt;Go Class: 08 Functions, Parameters &amp;amp; Defer&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://go.dev/blog/slices-intro#:~:text=Go%E2%80%99s%20arrays%20are%20values,think%20about%20arrays%20is%20as" rel="noopener noreferrer"&gt;Go Slices: usage and internals&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.alexedwards.net/blog/demystifying-function-parameters-in-go" rel="noopener noreferrer"&gt;Demystifying function parameters in Go&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://research.swtch.com/godata#:~:text=A%20,a%20potentially%20different%20pointer%20and" rel="noopener noreferrer"&gt;Go Data Structures&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
      <category>godev</category>
    </item>
  </channel>
</rss>
