Repository: go
Issue: proposal: cmd/go: support peer dependencies
Labels: Proposal,GoCommand,modules

## Background

I am the author of the [`gitlab.com/tozd/go/errors`](https://gitlab.com/tozd/go/errors), a modern drop-in replacement for `github.com/pkg/errors` which enables errors to be annotated with stack traces and structured details. It is a new package with fresh implementation and is not a fork of `github.com/pkg/errors`, but it does attempt to keep compatibility with it by reusing its API and by supporting reusing stack traces made by `github.com/pkg/errors`. The latter is important because in large codebases it can happen that both `github.com/pkg/errors` and `gitlab.com/tozd/go/errors` are used.

`github.com/pkg/errors` exposes its stack trace using the following interface:

```go
type stackTracer interface {
        StackTrace() errors.StackTrace
}
```

`errors.StackTrace` is a type (underlying type is `[]uintptr`) exported by `github.com/pkg/errors`. So to be able to access the stack trace, one has to import `github.com/pkg/errors` to be able to define the interface. To extract the stack trace (just the underlying `[]uintptr` data), I do [something (approximately) like](https://gitlab.com/tozd/go/errors/-/blob/53958cde2cfe5e17d65c9f75de7a76142129c2ab/errors.go#L230-254):

```go
switch e := err.(type) {
case interface {StackTrace() errors.StackTrace}:
	st := e.StackTrace()
	return *(*[]uintptr)(unsafe.Pointer(&st))
}
```

`github.com/pkg/errors` has been archived in 2021 and is not maintained anymore. Because of this [people are searching for maintained alternatives](https://github.com/search?q=+%22github.com%2Fpkg%2Ferrors%22++&type=issues). It is not that `github.com/pkg/errors` has any known security issues, but it does lack newer features (like `errors.Join`) and in general people seem to not enjoy having an unmaintained dependency. From what I have seen, even to a degree that they blocklist the dependency using linter tools.

## The issue

* People are trying to remove `github.com/pkg/errors` dependency.
* `gitlab.com/tozd/go/errors` might be a good alternative.
* But `gitlab.com/tozd/go/errors` also has a dependency on `github.com/pkg/errors` so that it works better in codebases where `github.com/pkg/errors` is used as well and can be interoperable with `github.com/pkg/errors`.

## The proposal

NPM has [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies) so solve exactly this problem. I think it could be useful for Go as well. The idea would be that a separate list of dependencies is made in `go.mod`. So you would have direct, indirect, and peer dependencies. And if that peer dependency is satisfied, an automatic build flag would enable, including the file which uses that peer dependency. (I am open to how that build flag format would look like.)

## Alternatives

Build tags seems to be one alternative. I could define a build tag one could use to enable/disable checking for `github.com/pkg/errors` stack trace on errors (and importing the `StackTrace` symbol). But the issue is that dependency in `go.mod` still stays which can trick tools into thinking that the package still uses `github.com/pkg/errors`.