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:
- if resolves to a package path and that package has a
func main, run that. - otherwise (current behavior), look in for a
mainpackage with afunc mainand 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 mainonly means command entry point if it’s inpackage 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 throughpackage main). But it could conceivably cause a test to fail, e.g the project had an explicit test for an error fromgo 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?
- 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 likego 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. - (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 mainandfunc main.
I can invoke the selected sample viago run <sample>.go(note it is a file path). I cannotgo testorgo buildthe module (because of duplicate definitions offunc main), but I live with that for now.