Nil pointer dereference in Go without panic or segfault (day 3/100 days of writing)
In Golang, we can define these things called “receivers.” It’s kind of similar to instance methods in an object oriented language like Java or Python. But Go is not object oriented but lets to OOP-y things. One of these things is defining functions with receivers. Let’s see what that means:
package main
import (
"fmt"
)
type cool struct {
data string
}
// cl is the receiver. now that this function exists, if we have an
// entity of type *cool, we can call printData on it
func (cl *cool) printData() {
fmt.Println(cl.data)
}
func main() {
x := &cool{data: "hi"}
// very oop-y
x.printData()
}
This outputs: “hi.” Try it in the Better Go Playground yourself: https://goplay.tools/.
Now let’s do what’s known as a pro gamer move.
Wait what?? Where’s the panic? Where’s the segfault? Well, this is why we said Go is “OOP-y,” but it’s not OOP. I was a little naughty and secretly modified our function to check for nil on the receiver!
The code now looks like:
package main
import (
"fmt"
)
type cool struct {
data string
}
func (cl *cool) printData() {
if cl == nil {
return
}
fmt.Println(cl.data)
}
func main() {
x := &cool{data: "hi"}
x.printData()
var y *cool
if y == nil {
fmt.Println("y is 100% nil. I really should not try to dereference y if I know what's good for me")
}
// obviously we're going to do it anyway
// this should panic...right?
y.printData()
}
What’s the takeaway here? Well, it’s that Go’s “dot operator” (i.e., `.`) is a little misleading. When you try to access a struct attribute on a nil pointer, you will segfault! But when you call a function defined with a receiver, the we don’t actually dereference the pointer until whatever we actually do in the function. But we still use the same operator (.) for accessing struct attributes and calling functions! Thanks for reading.