18

Every Go file starts with package <something>.

As far as I understand - and this is probably where I am missing some information - there are only two possible values for <something>: The name of the directory it is in*, or main. If it is main, all other files in that directory can only have main, too. If it is something else, the project is inconsistent/violating convention.

Now if it is the name of the directory, it's redundant, because the same information is, well, in the name of the directory.

If it is main, it's kind of useless, because as far as I can see there is no way to tell go build to "please build all main packages".

* Because, in other words, one directory is one package.

AndreKR
  • 32,613
  • 18
  • 106
  • 168
  • What if in case you need to acces some function or structure or interface defined in another file in project from `main` ? Also it helps to follow modular approach to build a project. – ameyCU Jul 25 '16 at 09:25
  • @ameyCU Then I just use it. All identifiers from all files within the same package (= directory) are in one single scope. – AndreKR Jul 25 '16 at 09:28
  • Its when you start making/importing a package to use it in your main package. – huygn Jul 25 '16 at 09:31
  • Actually there is a way to build all main packages underneath a certain root of the GOPATH subtree, for example: go install -v github.com/foo/bar/... will build and install all executables corresponding to the 'package main' packages underneath GOPATH/src/github.com/foo/bar – dmitris Jul 25 '16 at 11:43

2 Answers2

14

The name of the package does not have to coincide with the directory name. It is possible to have package foobar in the directory xyz/go-foobar. In this case, xyz/go-foobar becomes an import path, but the package name that you use to quality the identifiers (functions, types etc.) would be foobar.

Here's an example to make it more concrete: I created a test package http://godoc.org/github.com/dmitris/go-foobar (source in https://github.com/dmitris/go-foobar) - you can see from the documentation page, that the import path is "github.com/dmitris/go-foobar" but the package name is foobar, so you would call the function it provides as foobar.Demo() (not go-foobar.Demo()).

A similar real-life example - the import path for the NSQ Messaging platform is "github.com/nsqio/go-nsq" while the package name is "nsq": http://godoc.org/github.com/nsqio/go-nsq. However, for the sake of user-friendliness and simplicity, the standard and recommended practice is to keep the last portions of the import path and the package name being the same whenever possible.

package main is not useless - it tells the Go compiler to create an executable as opposed to a .a library file (with go install or go get; go build discards the compilation result). The executable is named after the directory name in which the package main file or files are placed. Again a concrete example - I made a test program https://github.com/dmitris/go-foobar-client, you install it with go get github.com/dmitris/go-foobar-client and you should get a go-foobar-client executable placed in your $GOPATH/bin directory. It is from the the directory name where the package main file is placed that the Go compiler takes the name of the executable from. The filename of the .go file that contains the main() function is not important - in the example above, we can rename main.go to client.go or something else, but as long as the enclosing directory is called go-foobar-client, that's how the resulting executable will be named.

For an additional accessible and practically oriented reading about Go packages, I recommend Dave Cheney's article "Five suggestions for setting up a Go project" http://dave.cheney.net/2014/12/01/five-suggestions-for-setting-up-a-go-project.

dmitris
  • 1,441
  • 1
  • 12
  • 13
  • "package main is not useless - it tells the Go compiler to create an executable as opposed to a .a library file." Hm, I can't reproduce that. When my package is called something other than `main`, `go build` does absolutely nothing. – AndreKR Jul 25 '16 at 11:04
  • 2
    @AndreKR See: [What does go build build?](http://stackoverflow.com/questions/30612611/what-does-go-build-build) – icza Jul 25 '16 at 11:13
  • thanks @icza - edited the answer to mention the difference between "go install" and "go build" in this respect. A "fringe" case when "go build" retains the compiled library is when you run it with "-work" option, ex. go build -x -work - the compiled .a can be then found underneath the WORK directory which does not get deleted with this option. – dmitris Jul 25 '16 at 12:01
13

The missing information you "have" is that the package name does not need to be the same as the directory name.

It is perfectly fine to use a package name other than the folder name. If you do so, you still have to import the package based on the directory structure, but after the import you have to refer to it by the name you used in the package clause.

For example, if you have a folder $GOPATH/src/mypck, and in it you have a file a.go:

package apple

const Pi = 3.14

Using this package:

package main

import (
    "mypck"
    "fmt"
)

func main() {
    fmt.Println(apple.Pi)
}

Just like you are allowed to use relative imports but is not advisable, you may use package names other that their containing folder, but this is not advisable also to avoid further misunderstanding.

Note that the specification doesn't even require all files belonging to the same package to be in the same folder (but it may be an implementation requirement). Spec: Package clause:

A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.

What's the use of this?

Simple. A package name is a Go identifier:

identifier = letter { letter | unicode_digit } .

Which allows unicode letters to be used in identifiers, e.g. αβ is a valid identifier in Go. Folder and file names are not handled by Go but by the Operating System, and different file systems have different restrictions. There are actually many file systems which would not allow all valid Go identifiers as folder names, so you would not be able to name your packages what otherwise the language spec would allow.

So in one hand not all valid Go identifiers may be valid folder names. And on the other hand, not all valid folder names are valid Go identifiers, for example go-math is a valid folder name in most (all?) file systems, but it's not a valid Go identifier (as identifiers cannot contain the dash - character).

Having the option to use package names different than their containing folders, you have the option to really name your packages what the language spec allows, regardless of the underlying operating and file system, and put it in a folder named anything that the underlying OS and file system allows - regardless of the package name.

icza
  • 389,944
  • 63
  • 907
  • 827
  • Interesting. Do you have a real-life example (Github?) where this is used to some benefit? – AndreKR Jul 25 '16 at 09:46
  • Regarding the spec: I think we shouldn't nitpick about Go language and Go implementation, there is only one relevant implementation of the Go language. :) – AndreKR Jul 25 '16 at 09:49
  • @AndreKR It gives you the option to use package names which otherwise might not be permitted by the underlying operating or file system. See edited answer. – icza Jul 25 '16 at 09:55
  • I wish I could accept both answers. I'll upvote this one and accept the other, because that's closer to the question, especially after your comment. – AndreKR Jul 25 '16 at 14:57