The tradeoffs of Go version behavior in go.mod module files
As covered in the official documentation, the
go.mod file that
contains various information about a Go module can specify a Go
version. This specified version does not actually do much in practice,
at least so far, and in particular older versions of Go will still
attempt to build the module. This behavior and others I mentioned
yesterday may strike people as peculiar or even
crazy. However, any behavior here has tradeoffs and I think that Go
has chosen what is a sensible option.
The core tradeoff is between what Go version is assigned to a newly created module and what older versions of Go will do with modules that name a newer version. If a newly created module gets the current version of Go and older versions of Go will not build newer modules, then your newly created module is not useful for anyone who is using an older Go version (even though there's probably nothing in the code of the module that requires the latest Go version). This encourages people to specify older versions by hand or just to keep using older Go versions to avoid accidents. It's also a recipe for projects to get annoying issue reports of 'can you change your go.mod to set an older version of Go that this works fine on (and do a new release)'.
On the other hand, if a newly created module gets an older version
of Go, then you can't immediately use any new features of your
version of Go in your new code without a confusing extra manual
step. This at least discourages people from using new Go features
they could benefit from. And if older versions of Go won't build
modules with newer Go versions, people still may not be able to
build your module on some Go versions that they may want to use
(such as the one supplied by their operating system, which may
be sadly out of date), unless
the default Go version in modules is all the way back at Go 1.12
(where the '
go' directive was introduced).
(Setting the Go version back also creates a battleground of people arguing how far back it should be. No one is going to be happy.)
If you allow older versions of Go to build modules claiming to require newer versions of Go, you more or less have to not change existing behavior, only add new behavior and new features that were previously some sort of error. If you change existing behavior, older Go versions will silently mis-compile the code, possibly introducing both bugs and security issues. If the version of Go in go.mod is a hard requirement, you can change existing behavior; if a module's author increases the Go version, it's their responsibility to make sure the result really works right. However, changing existing Go behavior is at least against the spirit of the Go 1 compatibility guarantee.
In addition, Go already has a way to implement hard Go version requirements, in the form of build directives. Build directives are also per file, not per package or module, which potentially allows you to write a module that uses new Go features but will still build and work for people with older Go versions.
The path Go has chosen (partly implicitly) allows people to use new Go
features immediately and without nagging in new Go code (or at least
new modules) but makes a best effort attempt to let such new code work
with older versions of Go. If the code genuinely needs new Go features,
it will most likely fail to build on older versions of Go with actual
errors, and you'll know that the
go.mod requirement is a real one.
Sidebar: The engineering reason to not change existing Go behavior
If the behavior of existing valid Go code depends on the version
of Go it's for, someone reading the code in the future must both
know what version of Go the code is for and remember that there's
a difference in behavior in that particular area of Go between
versions (and between what versions). But the version of Go is only
specified in the
go.mod file, not even in the Go source code file
you're reading, and people are bad at remembering the exact details
of changed behavior or even that it exists. Mistakes and bugs would
be practically guaranteed.