Comment by porridgeraisin
1 day ago
I wrote a small explainer on the typed-vs-untyped nil issue. It is one of the things that can actually bite you in production. Easy to miss it in code review.
Here's the accompanying playground: https://go.dev/play/p/Kt93xQGAiHK
If you run the code, you will see that calling read() on ControlMessage causes a panic even though there is a nil check. However, it doesn't happen for Message. See the read() implementation for Message: we need to have a nil check inside the pointer-receiver struct methods. This is the simplest solution. We have a linter for this. The ecosystem also helps, e.g protobuf generated code also has nil checks inside pointer receivers.
After spending some time in lower level languages Go IMO makes much more sense. Your example:
First one - you have an address to a struct, you pass it, all good.
Second case: you set address of struct to "nil". What is nil? It's an address like anything else. Maybe it's 0x000000 or something else. At this point from memory perspective it exists, but OS will prevent you from touching anything that NULL pointer allows you to touch.
Because you don't touch ANYTHING nothing fails. It's like a deadly poison in a box you don't open.
Third example id the same as second one. You have a IMessage but it points to NULL (instead NULL pointing to deadly poison).
And in fourth, you finally open the box.
Is it magic knowledge? I don't think so, but I'm also not surprised about how you can modify data through slice passing.
IMO the biggest Go shortcoming is selling itself as a high level language, while it touches more bare metal that people are used to touch.
great example, that is indeed tricky