Hacker News new | ask | show | jobs
by tapirl 1265 days ago
> panics are easy to trigger (e.g. methods with nil receivers)

No, methods nil receivers in Go don't trigger panics (if they are not dereferenced).

> every error must be handled explicitly, and every control flow path must be made obvious, no matter how much verbosity this creates.

Is this, bad? It is just the recommended way. You are not required to implement your code in this way.

3 comments

> No, methods nil receivers in Go don't trigger panics (if they are not dereferenced).

Yes, but in practice most methods do dereference their receivers. Given that, you have two choices:

1. Check for nil receivers explicitly in every method. This is considered unidiomatic and libraries rarely do this.

2. Don't check for nil receivers, and have your method panic on the first dereference with no explicit check. Then, most of your methods can halt partway through in unexpected (and usually undocumented) ways, unless you pay very close attention to this failure mode.

Furthermore, such panics can occur far down the call stack, making it non-obvious from the stack trace where the error is.

Also, this means that, if you upgrade your library so that a method now dereferences its receiver, your library is suddenly no longer backwards-compatible.

In my honest opinion, you describe a theory problem not happening in production practice.

It is the NORMAL behavior to let it panic when a nil receiver is dereferenced. DON'T try to check it!

To the second point: I think the issue is that you don't want to handle the errors in a function, but just propagate it, you still need to write error handling code, whereas in languages with exceptions you can just not do anything and let the exception propagate. Hence, the extra verbosity. Not checking for error is not an option in go.
What is the way you recommend?
The only way to do it in go is to always handle errors, even if you just want to pass them through. It’s one of the downsides of the language. My recommended way is to use a language with exceptions. They have downsides too, of course. It’s always a trade off, but I personally think the upsides of exceptions outweigh the downsides. At least the better implementations of them do.
Go supports exceptions: panics.
That's not a particularly nice implementation of exceptions and all libraries treat panics as invariant checks, things that should never happen. So, if you want to treat expected errors (eg. file not found) using panic you simple won't be able to go very far, unless you create some functions to convert all errors into panics. But, even then, panic is not great. They are not typed, so you never know what panics could be raised from a function and using a single deferred function that has to handle all errors whereve it is you want to handle them is quite awkward. Obviously, the reason for those design choices is that panics are really not exceptions.
Yes, panics are not totally the same as exceptions. You can view them as simpler and less powerful exceptions. The Go culture is almost different from Java form every perspective. Go prefers explicit errors over exceptions.
Why would you have a method that doesn’t touch the receiver? Refactor it into a function.
Dereferencing isn't the only way to touch a pointer:

    func (o *myObject) isNil() bool {
        return o == nil
    }
Right, but if you’re doing a nil check, you obviously won’t be worried about nil deferences.
Either to implement an interface, or because it branches to check if the value is nil before dereferencing it
Re: the second point, see my other comment.