3 ms·
> Most languages pride themselves on handing you a ton of tools and telling you to do whatever you want. You then don't have to be an expert in each individual
by gwd 6y ago
> Most languages pride themselves on handing you a ton of tools and telling you to do whatever you want. You then don't have to be an expert in each individual tool, just know how to use the toolbox to get the whole job done. Go hands you a smaller toolbox, and expects you to be an expert in each one. In my experience, it can generally get the job done just fine, but you need to be ready to use each tool very well.
I disagree with the characterization that "Go expects you to be an expert in each one". That's what C does, with all its arcane implicit type conversion rules, memory models and UB traps lying everywhere. Coming from C and learning Go, it was refreshing, for instance, for integer overflow to be defined, and for it to be impossible to even compare `int32` to `int64` without a cast.
Which is why my actual proposal is along similar lines: The "magic" of comparing an interface to a bare `nil` contains a trap, so disallow it. If you ended up with something like this:
if display == interface{}(nil) {
...
}
It should be pretty obvious that if `display` is `*UserDisplay(nil)`, this comparison will be false. That would prompt you either to use reflection, or to use something else to track whether `display` contained something valid (e.g., a separate boolean variable, like you propose).
Furthermore, I do stand by the comment I made in the discussion of my proposal regarding comparing `error` to `nil`: It turns out, probably the single most common pattern in Go is in fact not safe. Anyone anywhere could accidentally return `*MyError(nil)`, and suddenly all the error checking code all the way up the stack is completely broken. Yes, as you say, doing so would clearly be a bug; but the whole point of having a type-checked language is to be able to prevent this type of bug from cascading throughout the system.
Golang is still, in fact, my go-to language for new projects. And in most things it's just great -- I know how to use the type system to prevent all sorts of dumb mistakes, and 75% of the time, if it compiles, it Just Works. It's because Go is so good at preventing stupid errors that I find the "interface trap" so frustrating.
- jerf 6y agoYou are still speaking as if an interface containing a nil is the same as a nil interface. They are not. ∗MyError(nil) as an error value is perfectly valid. It means there is an error, and whatever created that value is promising that you can call .Error() on the resulting value and get a string. If you get a panic instead of a string, the code that made that promise is where the bug is, not the code that called .Error()... and in Go, it is perfectly possible for that nil to produce a string perfectly validly. Calling methods on a nil is not invalid Go. That is a concept ported over from C++ or similar languages inappropriately. It is as wrong as worrying that you can't create a value on the stack in a function and return it. Go does not work that way. Until you correct your understanding, you will continue to find Go frustrating. nil and invalid are not the same thing. This is not a matter of opinion; it is how the language works. As long as you persist in thinking otherwise, you will remain confused. If you checked whether err is nil by checking the interface value, and then penetrating the interface to see if the underlying concrete type is a pointer and than pointer is nil, that is a bug in the code doing that. You should never do that. It is never correct. It is objectively wrong to think of them as the same thing and to treat them the same, because they are not. The correct solution is what I outlined; do not create the lying interface values in the first place. Then they can not propagate through your code and mess you up. I'm not trying to debate whether Go is "right" or "wrong" here. It is perfectly acceptable to come to a correct understanding of how Go works and still think it is not the best way to build the language. Personally I'd still be happy to get non-nillable pointers, in the same way C# managed to add them later, so you can put me in that category myself. But you still have an incorrect understanding of how Go works, and I'm writing this not to defend Go but to try to save you that frustration. However, if you keep resisting the correct understanding, you will continue to be confused and frustrated and write bugs.