Presenters

Source

Decoding Go’s Quirks: A Journey Through Unexpected Behaviors 🤯

Hey Gophers! 👋 Ever felt like Go was acting a little… weird? You’re not alone! Sometimes, the language throws curveballs that challenge your assumptions and leave you scratching your head.

That’s what Sager, a seasoned Go developer, explored in his presentation at GopherCon 2025 - “Broken Go.” This wasn’ll just a talk; it was an interactive quiz designed to expose some of Go’s most delightfully quirky behaviors. Let’s dive in!

🎯 The Quiz Begins: Assumptions Challenged

Sager kicked things off with a series of interactive quizzes, and the first question immediately highlighted a common pitfall:

Scenario: A program modifies a slice, and we want to predict the output.

The Catch: Go slices can be deceptive! When you append to a slice, it might not behave as you expect, especially when dealing with capacity. The quiz revealed that appending can actually modify the underlying array, leading to unexpected results.

Why it Happens: When a slice is created, it references an underlying array. Appending can trigger reallocation, creating a new array and making the slice point to it. This can leave the original slice referencing stale data.

🛠️ Interfaces and Pointers: A Strict Relationship 🧐

Next up: a deep dive into Go’s interface rules.

Scenario: A program attempts to assign a value to an interface with a pointer receiver.

The Catch: Go is strict when it comes to interface assignments. You can’t assign a value to an interface expecting a pointer receiver.

Why it Happens: Go converts value objects into pointers when calling methods on a value object. However, interface assignments are more rigid. This mismatch leads to a compile-time error. The solution? Ensure consistency in receiver types (either both value or both pointer).

👻 Nil Objects: More Flexible Than You Think 😮

Many programmers are taught that calling methods on nil objects leads to crashes. Go, however, offers a bit of flexibility:

Scenario: Calling a method on a nil object.

The Catch: Go allows calling methods on nil objects!

Why it Happens: This design choice promotes flexibility, enabling optional initialization, graceful degradation, and lazy loading. While seemingly a bug, it’s a deliberate feature with a purpose.

🌍 Emojis and UTF-8: Bytes vs. Runes 🤯

Emojis can be tricky in Go!

Scenario: Determining the length of a string containing emojis.

The Catch: len() returns the number of bytes, not the number of characters (runes).

Why it Happens: Go strings are UTF-8 encoded. Emojis are often represented by multiple bytes. Using range iterates over runes (Unicode code points), giving the correct character count.

💾 Memory Management: Maps and Backing Arrays 🧠

Go’s memory management isn’t always straightforward.

Scenario: Deleting entries from a map and triggering garbage collection.

The Catch: Maps don’t immediately free all memory upon deletion.

Why it Happens: Go maps are optimized for additions and deletions. Deleting entries leaves “holes” for future operations, retaining the backing array. Full memory reclamation occurs when the map goes out of scope.

Key Takeaways:

  • Go is full of surprises: Don’s be afraid to question your assumptions.
  • Understand underlying mechanisms: Dig into how slices, interfaces, and memory management actually work.
  • Embrace the quirks: Some of Go’s “broken” behaviors are design choices that promote flexibility and efficiency.

So, keep exploring, keep experimenting, and keep uncovering the delightful quirks that make Go the unique language it is! 🚀✨

Appendix