sleepytea
sleepytea

Reputation: 284

Returning an optional value and an error

What's the best signature for a function that returns an optional value and a possible error?

For example:

func findColor(name string) (RGB, error) {
    ...
}

(The empty RGB value is black, a valid color, so you can't use it to infer that no value was found. Assume the error might come from something like a database connection.)

The two options that seem best are a boolean return value:

func findColor(name string) (RGB, bool, error) {
    ...
}

c, ok, err := findColor(myname)

if !ok {
    ...
} else if err != nil {
    ...
}

...

Or a special error value:

var ColorNotFound = errors.New(...)

func findColor(name string) (RGB, error) {
    ...
}

c, err := findColor(...)

if err == ColorNotFound {
    ...
} else if err != nil {
    ...
}

...

(Making special errors seems like a pain.)

What's the most idiomatic approach?

Upvotes: 9

Views: 17151

Answers (2)

Ainar-G
Ainar-G

Reputation: 36249

You could make findColor return *RGB and then compare it to nil:

c, err := findColor(name)
if err != nil { /* Handle error. */ }
if c == nil { /* Handle no color. */ }

This is unsafe though, since if you try to call methods on a nil pointer, they can cause a panic.

I'd recommend sticking with a special ErrColorNotFound approach.

Upvotes: 3

Nick Craig-Wood
Nick Craig-Wood

Reputation: 54117

The convention in Go is to return (value, error) and if error != nil then value is (or may be) invalid.

If you have special errors you need to do something with (like io.EOF) then making a specific error is normal practice. So I would say your 3rd example is the most idiomatic, if you want to do something different for ColorNotFound.

var ColorNotFound = errors.New(...)

func findColor(name string) (RGB, error) {
    // ...
}

c, err := findColor(...)

if err == ColorNotFound {
    // Do something special if ColorNotFound...
} else if err != nil {
    // Some other kind of error...
}

Upvotes: 18

Related Questions