Constructor/Initializer functions that can fail

Hi, all,

I’m writing a lib to interact with a web service for a lesser known cloud storage service. One of the functions in this lib is NewUserClient which (as you may expect) creates a new Client object that’s used to interact with this web service. This call needs to do some back and forth with the API to convert a username and password to an API token that can be included in a header to authorize subsequent requests. Because of this back and forth with an http.Client, an error can be returned. I’m not a very experienced Go programmer but based on my limited exposure to a handful of Go packages, it does not seem common to create a NewX function return (X, error). This leads me to wonder if I should either:

  • Avoid multiple return values from a NewX function; either:
    • Defer any errors until the first function that has an error in its return values
    • Panic (I don’t think this is the right way to do this, but it’s very Pythonic/C#-ic/Java-ic (note also that I know Go is not Python/C#/Java :slight_smile: )).
    • put an Err() function or something similar on the returned object that can get whatever the last error was.
  • Use a different naming convention (e.g. CreateX).

I don’t know which if any of these options is the right fit. Are there others I haven’t considered? Are any a good default / de-facto standard that I should prefer unless I have a reason not to?

It may make more sense to make this something like Authenticate(username, pw string) (*Clent, error) because then it becomes clear that you need to authenticate the data before returning a client.

Another option is to have NewClient return a client with a method like Authenticate and have that return an error if it is invalid.

I see and do this all the time, and would not be at all surprised by it. It’s very common in the standard library as well.

3 Likes

Thanks for your reply, Jon, I like the idea of having a function with a name other than NewX that makes it clear that this doesn’t just return an X but at the same time I don’t think it’s obvious that a name like Authenticate will give me a new Client without me having to check my own documentation in the future (assuming I don’t end up using this package very frequently). I like the idea of stumbling into the “pit of success” if at all possible!

For the same reason, I don’t really like the idea of using a separate Authenticate method to authenticate the Client because it’s possible that a user of the API will forget to use this function after they construct the Client. I’d like the construction/initialization of the client to be a single function call (from the public API) to eliminate the possibility of using the Client incorrectly.

Thanks, Jakob, I think I’m going to go with this. I like the idea of not even getting a Client value if initialization fails.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.