Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

    > Most of my code will annotate a lower error with the context of the operation that was happening.
This is easy to solve with chained exceptions to add context.

    > it generates much better debugging info than a stack trace in a lot of situations, especially for non-transient errors because you can annotate things with method arguments.
You cannot add method args to an exception message? I am confused.


If it's easy then why does nobody do it? ;)

In all exception-based languages I know of, catching an exception is so syntactically heavy that annotating intermediate exceptions is never done:

    try {
        Foo()
    } catch (err) {
        throw new Exception("message", err)
    }
One line just turned into four and the call to Foo() is in a nested scope now, ew. At that point even Go is more ergonomic and less verbose:

    err := Foo()
    if err != nil {
        return fmt.Errorf("dfjsdlfkd %w", err)
    }


> If it's easy then why does nobody do it? ;)

People do this all the time with exceptions.

> One line just turned into four

The Go version has one line of difference?

> At that point even Go is more ergonomic and less verbose

You can't compare it to your Go version because you have to write the error check at every single level, whereas once I throw that exception I can catch it wherever I want. Obviously the Go version will have much more code just around one error.


It is definitely possible with exceptions, but it is not the norm (you can do it yourself, but will a library also do it?) because the norm in Java is to silently pass up exceptions as that is the most ergonomic thing.

And once you start doing it with exceptions, there’s not much difference in the code you end up writing between errors and exceptions.

In practice, I’ve found that when I write Go, I end up annotating most error returns, so the benefit of exceptions for me would be minimal.


> And once you start doing it with exceptions, there’s not much difference in the code you end up writing between errors and exceptions

The difference is where you want to catch the error, and not doing a bunch of "plumbing code" for intermediate callers that don't need to know about that error.

> because the norm in Java is to silently pass up exceptions as that is the most ergonomic thing

Adding args to an exception is completely localized. Adding additional args to an error in Go could mean changing dozens of files.

Not to mention I can actually make my own exceptions for the problem. They are like enums with data.


> difference is where you want to catch the error

Catching is pretty similar no? In Java you match by type and in Go, you match by `errors.Is`? I guess the static checking in Java js better, but in terms of code written it is no different.

> additional args to error in Go could mean changing dozens of files

Just to be clear, here we are talking about a function that already returns an exception/error and adding args to it? That is also a local change in Go as well. The call site already handle the interface for error, not sure why changing a field or modifying the error message would make a difference.

Arguably, this type of thing is harder in Java. Adding a new type of exception requires modifying all dependent callers to declare/handle the exception (unless they handle the generic Exception), whereas in Go it is a local only change (except if you need to actually handle the error).


> Catching is pretty similar no?

In Go, you have to "catch" it at every call level.

> Just to be clear, here we are talking about a function that already returns an exception/error and adding args to it

Yes, but adding an arg doesn't mean modifying the error string, it means adding another piece of data which could be a different type. That's another var, and now every call level has to update to pass along that new var. Unless you change the var from a string to a map, which is a whole different set of headaches.

> Arguably, this type of thing is harder in Java. Adding a new type of exception requires modifying all dependent callers to declare/handle the exception

Only if they need to handle it. If you just want it to bubble up, that function doesn't even need to know about that error or what args it has. That's not the case in Go. Every function has to know about every error that passes through. It's the difference between changing two files and changing 10 files.


> That’s another var

By another var, do you mean another return value? That’s not how it works in Go at all. It is possible to do it that way, but that would not be idiomatic.

You have a single error returned regardless of how many “errors” you have (> 0). If you need to return a new error and it is a custom struct that includes fields, you just implement Error interface on the struct and return it as the single error return. If you need to add new args on the struct, nothing changes other than the error implementation.

Do you want to return 2 errors from the same call site? You have to use something like multierror or a custom struct that includes 2 errors and implement the interface yourself. But the actual thing you return is still a single error.

> unless you want to change the var from string to map

Errors are not strings. It is an interface. If you want to return a string, you implement the interface (although it is much simpler to create a new error with errors.New). If you want to change it to a map later, you implement the interface on the map. It is transparent to the caller, because errors are dynamically dispatched the majority of the time.

> only if they need to handle it

Well, every function needs to declare which exceptions it throws, so you will have to modify every function in the call stack if you don’t want to handle it and it is a new type of Exception.

> That’s not the case in Go

That IS the case in Go. The most common pattern is to return an implementation of the error interface. Nothing changes if the underlying type of error changes except (potentially) the sites that want to handle a specific type of error.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: