mirror of
https://github.com/MedUnes/go-kata.git
synced 2026-03-12 21:55:53 +07:00
2.4 KiB
2.4 KiB
Kata 20: The “nil != nil” Interface Trap (Typed nil Errors)
Target Idioms: Interface Semantics, Typed nil Pitfall, Safe Error Returns, errors.As
Difficulty: 🔴 Advanced
🧠 The "Why"
In Go, an interface value is only nil when both its dynamic type and value are nil.
If you return a typed nil pointer (e.g., (*MyError)(nil)) as an error, the interface has a non-nil type, so err != nil becomes true even though the pointer inside is nil.
This bites real code in production (especially custom error types and factories).
🎯 The Scenario
A function returns error. Sometimes it returns a typed nil pointer.
Your caller checks if err != nil and takes an error path, logs misleading failures, or even panics when accessing fields/methods.
🛠 The Challenge
Write a minimal package that:
- demonstrates the bug, and
- fixes it with an idiomatic pattern.
1. Functional Requirements
- Implement
type MyError struct { Op string }(or similar). - Implement a function
DoThing(...) errorthat sometimes returns(*MyError)(nil)aserror. - Demonstrate:
err != nilis truefmt.Printf("%T %#v\n", err, err)shows the typed nil behavior
- Provide a corrected version that returns a true nil interface when there is no error.
2. The "Idiomatic" Constraints (Pass/Fail Criteria)
- Must show the failing behavior in a test (
go test). - Must show the fix in a test.
- Must not “fix” by panicking or by sentinel errors.
- Use one of these idiomatic fixes:
- return
nilexplicitly when the pointer is nil - or return
error(nil)in the relevant branch
- return
- Demonstrate safe extraction using:
var me *MyError; errors.As(err, &me)and checkme != nil
🧪 Self-Correction (Test Yourself)
-
The Trap Repro
- Make
DoThing()returnvar e *MyError = nil; return e - Pass: your test proves
err != nilis true.
- Make
-
The Fix
- If internal pointer is nil, return literal
nil. - Pass:
err == nilworks, callers behave correctly.
- If internal pointer is nil, return literal
-
Extraction Safety
- Wrap the error and still extract with
errors.As. - Pass: extraction works through wrapping layers.
- Wrap the error and still extract with