| Your "state of the art" Go code is not really a good example of how that functionality would be written. If you want to check for a specific error condition, then just define a value for that error and use `errors.Is` to check for it. This works as you'd expect with wrapping: https://go.dev/play/p/rJIlKKSYn9Q > With the current go error handling, you need to add the informations yourself in the string, not as a real data structure. This is completely false! If you want to provide a structured error, then you just need to define a type for it. In your example, a Go programmer might use errors.Is(err, fs.ErrNotExist) and errors.As if they wanted to retrieve the specific file path that does not exist in a strongly-typed way, something like https://go.dev/play/p/hdHPLAVbQuW. > Delegating error handling to a try/catch block with a typed data structure allows the caller to care for certain type of errors and delegate the others to its own caller. With the current error type in Go, what would you do? parse the error message? Certainly not! I think there is a misconception that "an error is a string" -- in Go, an error is actually any type that satisfies the error interface, i.e. has an `Error() string` method. It can be any type at all, and have as many other methods as you like in order to provide the functionality you need. > what if the function is defined in a dependency you have no control over? There's nothing stopping you from writing `throw new Exception(String.format("file not found: %s", filename))` in languages with exceptions either. In both cases, it would be recognized as poor API design. Regarding stack traces, Go makes a strong distinction between errors (generally a deviation from the happy path) and panics (a true programming error, e.g. nil pointer dereference, where the program must exit). Errors do not provide stack traces since there is no need for them in a flow control context, panics do provide stack traces for useful debugging information. |