Hacker News new | ask | show | jobs
by zeeboo 2552 days ago
To be clear, you can name the return value whatever you want. People just typically name their error values `err`. Also, the mechanisms to mess with named return values in defer already exist: https://play.golang.org/p/7nFyiuAa3Ra
1 comments

Just to clarify, I was aware that named returns already exist in Go.

My main point is that this somewhat weird pattern is encouraged by the proposal since no other wrapping mechanism exists. And IMO wrapping is really essential for debuggable code.

I totally agree that good error wrapping is essential. In fact, I've been using this exact system for wrapping my errors for years, and it's been great (https://godoc.org/github.com/zeebo/errs#WrapP).

I suspect it's only "somewhat weird" due to lack of familiarity, and that adding an additional mechanism to wrap errors when one already exists is not in the spirit of a language built from small orthogonal components.

I don't like that it's mutable state that is easy to shadow accidentally. (tooling can warn you about it, but it's suboptimal).

Also, in a function with a couple of different error types, do you end up checking the error type manually and reacting accordingly, all in one final defer? That seems error prone. And it doesn't work at all if multiple statements can produce the same error - you won't know which statement caused it.

And, last but not least, this would loose proper backtrace information: the backtraces all point to the defer line rather than separate lines for each error.

You can’t naked return with a shadowed named return variable. The compiler disallows it. Thus, at any return site, you locally know that you’re either returning the only err in scope (the named return), or the specific value listed in the return will be assigned to the named return variable.

I don’t know what error types has to do with it. If you need to annotate differently for every exit point, sure, a defer doesn’t work, but neither would any other proposals I’ve seen. In those cases, do the more verbose thing because the verbosity is apparently warranted. In my experience, it is rarely warranted, and a stack trace with annotation about the package/general operation is sufficient.

The stack traces contained still include what line the return happened on when queried from inside the defer. They retain the information about which return executed. My, or any, helper could, if desired, explicitly skip the defer stack frame, and it would be indistinguishable from capturing at the return itself.

> I don't like that it's mutable state that is easy to shadow accidentally.

It can't happen. The compiler forbids it: https://play.golang.org/p/65bFHrgGblb

> Also, in a function with a couple of different error types, do you end up checking the error type manually and reacting accordingly, all in one final defer?

If a function needs to check the error returned by another function and act accordingly, then don't use try() and use a if statement.

If we just need to decorate the errors with proper context before returning them to the caller, then we use try everywhere and a single defer statement for the decoration. We can use a single defer statement because we expect that the error context is the same in the whole function. See this comment by Russ Cox: https://github.com/golang/go/issues/32437#issuecomment-50329...

> this would loose proper backtrace information: the backtraces all point to the defer line rather than separate lines for each error

No. In the deferred function, you can get the line of the actual return: https://play.golang.org/p/7MVZupCLh5F