Hey gophers, I would like to know your opinion on the following topic.

In my experience, the most popular case for errors.Join 
<https://pkg.go.dev/errors#Join> is to handle deferred potential errors 
such as closing os.File, sql.Rows or http.Response.Body.

Might be a bit of a contrived example, it get the main point though:
```go
func WriteJSONTo(v any, filename string) (err error) {
  file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
  if err != nil {
    return err
  }

  defer func() { err = errors.Join(err, file.Close()) }()

  return json.NewEncoder(file).Encode(v)
}
```

Although such deferred errors are still worth handling, I assume that they 
are unlikely to happen. That is, most function calls look like either 
`errors.Join(nil, nil)` or `errors.Join(someNonNilErr, nil)`

And the function itself always returns either nil or a wrapped trough 
`*errors.joinError` implementation, even if only one non-nil error is 
provided.

So, what do you think it makes sense for the function to return a wrapped 
error even if it contains only one error? Wouldn't it be more rational in 
such cases for Join to return that single error?

In addition, if such a use case occurs quite often, then avoiding 
unnecessary allocation could be a pleasant bonus:
```go
func BenchmarkJoinTwoErrors(b *testing.B) {
  for i := 0; i < b.N; i++ {
    _ = Join(io.EOF, io.ErrNoProgress)
  }
}

func BenchmarkJoinOneError(b *testing.B) {
  for i := 0; i < b.N; i++ {
    _ = Join(io.EOF, nil)
  }
}
```

```
goos: linux
goarch: amd64
pkg: fallout
cpu: 12th Gen Intel(R) Core(TM) i9-12900K
                 │    1.txt     │                5.txt                │
                 │    sec/op    │   sec/op     vs base                │
JoinTwoErrors-24    20.87n ± 2%   21.18n ± 2%        ~ (p=0.075 n=10)
JoinOneError-24    17.010n ± 2%   1.321n ± 1%  -92.23% (p=0.000 n=10)
geomean             18.84n        5.290n       -71.92%

                 │   1.txt    │                  5.txt                  │
                 │    B/op    │    B/op     vs base                     │
JoinTwoErrors-24   32.00 ± 0%   32.00 ± 0%         ~ (p=1.000 n=10) ¹
JoinOneError-24    16.00 ± 0%    0.00 ± 0%  -100.00% (p=0.000 n=10)
geomean            22.63                    ?                       ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean

                 │   1.txt    │                  5.txt                  │
                 │ allocs/op  │ allocs/op   vs base                     │
JoinTwoErrors-24   1.000 ± 0%   1.000 ± 0%         ~ (p=1.000 n=10) ¹
JoinOneError-24    1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean            1.000                    ?                       ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean
```

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/1dbeffa6-5a61-491a-9940-b999f77841c4n%40googlegroups.com.

Reply via email to