`go run <non-main-package>` -- why not?

Currently, for go run <arg> to work, the <arg> must have a package main and a func main. If it has the latter, but not the former, you get error:

package command-line-arguments is not a main package

Why not change go run to allow it to run any package that has a func main?
This needs 2 changes to the go run <arg> command:

  1. if resolves to a package path and that package has a func main, run that.
  2. otherwise (current behavior), look in for a main package with a func main and run that or, if not found, give an error. The error should be changed from:
package command-line-arguments is not a main package

to

package command-line-arguments does not have a main function and is not a main package

(or words to that effect)

Pros:

  • makes go toolchain more regular, and, I assert, simpler. Removes what appears to be an arbitrary restriction (“func main only means command entry point if it’s in package main”)
  • is a backward compatible extension of the API. Doesn’t break any program that was previously working.

Cons:

  • There might be some existing cmd projects that already have main() in non-main packages. This proposal wouldn’t break any existing way of invoking such a project (since they all go through package main). But it could conceivably cause a test to fail, e.g the project had an explicit test for an error from go run <non-main-package>. So there are code changes that a project might have to make simply to retain all-tests-pass status if the proposal were implemented.

Here’s my use case:
I have a collection of documentation samples, each of which is a short, standalone program (meaning reader could run it by a go run command). I want to maintain the sources in a single project (i.e. in a single module). How should I structure the project so I can run any chosen sample?

  1. I could put each sample in a separate package but with a func main, then implement a top-level driver that knows how to invoke each individual code sample package. The invocation would be something like go run driver <sample>.
    There’s the redundancy of having to provide this driver and also of having to put each sample program in a separate subdirectory because it’s in a separate package.
  2. (What I’m currently doing as a workaround) I maintain each sample program in a separate source file (in the project root). Each file has package main and func main.
    I can invoke the selected sample via go run <sample>.go (note it is a file path). I cannot go test or go build the module (because of duplicate definitions of func main), but I live with that for now.

Hi @BobHy, how about:

  1. Like 1, but without a func main() in each package. Instead, use a command dispatcher like urfave/cli or Cobra to write one func main() that provides each package as a subcommand.

  2. Like 2, but move the files into separate subfolders to enable testing and building.

My code samples are just barely a stand-alone program, really minimal runnable wrappers for the essential code snippet payload. The advantages of dispatching via CLI or running tests on them don’t really benefit me in this case.

I guess I’m asking this question: what’s the advantage to the go language and ecosystem of retaining the restriction that go run can only run a “main” package? I’m not asking whether we should do away with the very definition of a main package, I can see that it could still be the default entrypoint when there are multiple to choose from.

Hello there. Why not to use build tags and have as many main packages/functions as you need?