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

Disclaimer: just trying to directly answer the question, but also may be wrong in many ways. Please correct me.

I thought one difference was that a panic in a goroutine kills the whole process vs. an exception in a Java thread would just kill that thread. That could be more of a consequence of "Goroutines are not threads" rather than "panics are not exceptions".

Java Checked exceptions are certainly quite different than Go panics in terms of compile-time checks and what code the user of the language must write.

I thought there are some differences with how stack traces are accessed on caught/recovered exceptions? It's been a while now but I thought you needed something special to get the Go stack trace out. Fairly minor detail though.

Error is an interface in Go vs. a base class that's extended. Probably more of a result of other language design decisions rather than a decision in this particular area.

I haven't really seen the catch-and-rethrow paradigm for Go panics, but it's kinda different because `panic` only accepts a string argument whereas you can rethrow an "object" in Java (side note - sometimes Go error handling ends up having a lot of string concatenation ex. errors.Wrap because of the focus on "errors are strings"). The lack of catch-and-rethrow is more of a usage difference than a design difference, to your main point.

Probably others but can't think of them right now.



> I thought one difference was that a panic in a goroutine kills the whole process

Only if not caught. But in any case this still means that you need to write exception safe code, because you don't know if the function you call will throw, and you don't know if the function calling you will catch.

> `panic` only accepts a string argument

No: https://go.dev/play/p/ZDKpybtxABL

> catch-and-rethrow paradigm for Go panics

Probably because "you're not supposed to". You can.


Thanks for the clarification on the panic function signature - I missed it when checking the spec but it's definitely in there and defined as taking `interface{}`

https://go.dev/ref/spec#Handling_panics


> sometimes Go error handling ends up having a lot of string concatenation ex. errors.Wrap

Do you mean errors.Unwrap? There is no errors.Wrap function.

It does no string concatenation. It merely checks to see if the error value has an Unwrap method and returns the result of that method if available, or nil otherwise.

The only thing that comes close to having anything to do with strings in the error package is errors.New. Even then, the focus is not on the string. It is on the returned value, used when you want to store a 'constant' value for use with errors.Is.

> because of the focus on "errors are strings"

What does that mean? The focus is on types and values that satisfy the error interface. string does not satisfy the error interface. Strings cannot be errors, at least not when errors are passed as an error interface type, as is the convention.


> Do you mean errors.Unwrap? There is no errors.Wrap function.

I was referring to this errors.Wrap function: https://pkg.go.dev/github.com/pkg/errors#Wrap

I'm not a Go expert, is this function deprecated/removed?

RE: errors are strings

I probably didn't explain it too well but, for example, you're required to have a string to create an error of course

    // errors
    func New(message string) error
and then after a bunch of wrapping it ends up coming out like: "get product: fetch user: json unmarshal: invalid data"

So it's a bunch of string concatenation. Yes, as you said `error` is not a string it's an interface, but a lot of times it's basically acting like a string that's continuously growing. Rather than something more structured that's composed together, and then later (possibly) serialized to a string.

The "errors" interface mixes the concerns of error tracking with error serializing. I might not need to serialize the error to string because I'm serializing to other formats (protobuf, idk) but I have to use everything that revolves around a string-based API. That's what I meant by "errors are strings", even though that's hyperbole and not literally the case.


> I was referring to this errors.Wrap function [...] is this function deprecated/removed?

Got it. As the github.com identifier implies, that is a third-party library.

I suppose you could argue that said library is focused on strings, but then you could write a similar library in any language. Would you say that would also make those languages focused on strings? Probably not.

I don't think anyone would recommend that you use said library.

> you're required to have a string to create an error of course

It is true that said function does exist in the errors package (the standard library one), but is for defining error 'constants' meant to be evaluated on equality. Consider:

   var MyError = errors.New("my error")

   if (err == MyError) {
      // We got MyError!
   }
It is not the string that is significant. It is the comparable memory address that is significant.

Note: For reasons, you are bound to want to use errors.Is rather than == in this case, but the intent is the same. I choose to use == here as I think it explains it better.

> Rather than something more structured that's composed together, and then later (possibly) serialized to a string.

No, that's exactly what a Go error is. They are fully-fledged types, able to pack any kind of data you want in them. Consider:

   type MyError struct {
      Code int
      User User
      // ...
   }

   // Error is needed to satisfy the error interface.
   func (m MyError) Error() string {
      return fmt.Sprintf("code %d caused by %s", m.Code, m.User.Name)
   }

   func doSomething(user User) error {
      return MyError{Code: 1, User: user}
   }
That's an error in Go. You are right about strings to the extent that serialization to a string is a requirement of the error interface, but you don't ever need to use it. It is not significant to any meaningful degree. But as logging/reporting is a common way to deal with errors, it is understandable why the serialization is a requirement.

Of course, you don't have to use the error interface at all. Some functions in the Go standard library, as an example, use an int type to signify an error. You probably want to use `error` in the common case, though, so that your code plays nice with the expectations of others. Deviation should carry careful consideration.




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

Search: