Golang: "package ast_test" underscore test - go

Source file from Golang's stdlib
File's base directory: ast
Package specified in the file: ast_test ???
Package specified in all other files inside the same directory: ast
From golang.org:
src contains Go source files organized into packages (one package per directory) ...
By convention, packages are given lower case, single-word names; there should be no need for underscores or mixedCaps
... Another convention is that the package name is the base name of its source directory
How is it possible to have multiple packages (here 2) in one folder?

You find another example in src/pkg/go/ast/commentmap_test.go, with the comment:
// To avoid a cyclic dependency with go/parser, this file is in a separate package.
I suppose it allows for an othogonal command like:
go test
That will test parser features while avoiding for that test to be part of the same parser features (since it has been put in a separate package)
From go command man page:
Test files that declare a package with the suffix "_test" will be compiled as a separate package, and then linked and run with the main test binary.
This thread asked the question:
Now that the go tool requires each directory to be one package and doesn't allow to have files with different package names inside the same folder, how is the package keyword useful? It seems like a unnecessary repetition.
Is it required by the compiler or is there any plan to remove it?
The answers hinted at the fact that you can have more than one package in a folder:
The package declaration declares the name of the package.
The language Go doesn't know what a file or a directory is and the import path itself doesn't effect the actual name of the package that is being imported. So the only way the compiler knows what to call the package is the package declaration.
The language doesn't require separate packages to be in separate directories; it is a requirement of the go tool.
Another hypothetical implementation may not have this requirement.
Even this go tool requirement can be bypassed thanks to the "// +build" build tags.
For example, read misc/cgo/gmp or misc/cgo/stdio (some files include // +build ignore)

Related

VSCode look for Go packages in different directory

I successfully used rules_go to build a gRPC service:
go_proto_library(
name = "processor_go_proto",
compilers = ["#io_bazel_rules_go//proto:go_grpc"],
importpath = "/path/to/proto/package",
proto = ":processor_proto",
deps = ["//services/shared/proto/common:common_go_proto"],
)
However, I'm not sure how to import the resulting file in VSCode. The generated file is nested under bazel_bin and under the original proto file path; so to import this, it seems like I would need to write out the entire path (including the bazel_bin part) to the generated Go file. To my understanding, there doesn't seem to be a way to instruct VSCode to look under certain folders that only contain Go packages/files; everything seems to need a go.mod file. This makes it quite difficult to develop in.
For clarity, my directory structure looks something like this:
WORKSPACE
bazel-bin
- path
- to
- generated_Go_file.go
go.mod
go.sum
proto
- path
- to
- gRPC_proto.proto
main.go
main.go should use the generated_Go_file.go.
Is there a way around this?
I don't use Bazel and so cannot help with the Bazel configuration. It's likely there is a way to specify the generated code location so that you can revise this to reflect you preference.
The outline you provide of the generated code, is workable though and a common pattern. Often the generated proto|gRPC code is placed in a module's gen subdirectory.
This is somewhat similar to vendoring where your code incorporates what may often be a 3rd-party's stubs (client|server) into your code. The stubs must reflect the proto(s) package(s) and, when these are 3rd-party, using gen or bazel-bin provide a way to keep potentially multiple namespaces discrete.
You're correct that the import for main.go, could (!) be prefixed with the module name from go.mod (first line) followed by the folder path to the generated code. This is standard go packaging and treats the generated code in a similar way to vendored modules.
Another approach is to use|place the generated code in a different module.
For code generated from 3rd-party protos, this may be preferable and the generated code may be provided by the 3rd-party in a module that you can go get or add to your go.mod.
An example of this approach is Google Well-Known Types. The proto (sources) are bundled with protoc (lib directory) and, when protoc compiles sources that references any of these, the Go code that is generated includes imports that reference a Google-hosted location of the generated code (!) for these types (google.golang.org/protobuf/types/known).
Alternatively, you can replicate this behavior without having to use an external repo. The bazel-bin folder must be outside of the current module. Each distinct module in bazel-bin, would need its own go.mod file. You would include in a require block in your code's go.mod file references to the modules' (one or more) locations. You don't need to publish the module to a external repo but can simply require ( name => path/to/module ) to provide a local reference.

Go - What is the difference between "file block" & "package block"?

Spec mentions that:
Each package has a package block containing all Go source text for that package.
Each file has a file block containing all Go source text in that file.
package block is the Go source text that starts with package clause
my understanding is every Go source text always start with package clause
How different is "file block" from "package block"?
The obvious answer is that a file block contains the Go source text of a file, and the package block contains Go source text for a package. And a package is constructed from one or more source files.
Spec: Packages:
Go programs are constructed by linking together packages. A package in turn is constructed from one or more source files that together declare constants, types, variables and functions belonging to the package and which are accessible in all files of the same package.
It's true that a package is always handled as one unit regardless of how the source code is "distributed" between its files, but there are constructs that are "file scoped". Spec: Declarations and scope:
Go is lexically scoped using blocks:
[...]
3. The scope of the package name of an imported package is the file block of the file containing the import declaration.
The most obvious is the import declarations. If a package consists of multiple files and you import another package in one file, you can't use that in another file (of the same package).
Another important construct is the Build constraints. A build constraint placed in a source file only applies to the given file and not to other files in the same package.

Any useful alternative to foo.go + foo_test.go

For unit testing a Go code base, is there any reasonable alternative to the foo.go and foo_test.go pattern? The only "concern" is having all those extra files in the same place on the filesystem. It might be nice to put the test files in a central place, but that might not work due to the way Go packages work.
When you tell the go command to test a package, e.g.
go test some/path/mypackage
Then the go tool will look for test files in the package's directory. If you put the test files elsewhere, then the go tool will not find them (it will not even look for them) in other folders, so they will not be run / executed.
This argument alone is enough to not put them elsewhere.
Package doc of testing:
To write a new test suite, create a file whose name ends _test.go that contains the TestXxx functions as described here. Put the file in the same package as the one being tested.
Command go: Testing functions:
The 'go test' command expects to find test, benchmark, and example functions in the "*_test.go" files corresponding to the package under test.
Some notes:
The go tool only expects test files to be in the same folder, but you can name them however you like, you just have to use the _test.go suffix. E.g. you may have a foo.go, and you may use my_test.go for the tests. There is also no requirement to have a separate test file for each .go source files, you may put all tests into a single test file, and you may have more test files than source files.
In the test files, you may use the same package name, and then the test files are compiled together with the package so tests have access to everything–including unexported identifiers–in the package (white-box testing). You may use the package name suffixed with _test, in which case the tests in those files will only have access to the package's exported identifiers (black-box testing). Read more about this here: How can I allow one package access to another package's unexported data only when testing?
You shouldn't worry about the number of .go files. To go tool will handle even if you have a thousand .go files in a package. Although in most cases if you have many .go files in a package, that's an indication that the package is doing too much, and it should be broken into multiple, smaller packages.

What is the purpose of the package declaration?

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.
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.
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.

How do packages with multiple files work in golang?

This repo has 3 go files all begin with "package lumber".
To use this package, I'm supposed to put this in my GOROOT and simply
import lumber
in my program. How do variables and types in this package connect with each other across multiple files? How does the go compiler know which file to begin reading first?
In case I want to read the package, where should I begin reading to understand the package? What exactly is the flow of things here?
To elaborate on jnml's answer:
When you use import "foo/bar" in your code, you are not referring to the source files (which will be located in $GOPATH/src/foo/bar/).
Instead, you are referring to a compiled package file at $GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a. When you build your own code, and the compiler finds that the foo/bar package has not yet been compiled (or is out of date), it will do this for you automatically.
It does this by collating* all the relevant source files in the $GOPATH/src/foo/bar directory and building them into a single bar.a file, which it installs in the pkg directory. Compilation then resumes with your own program.
This process is repeated for all imported packages, and packages imported by those as well, all the way down the dependency chain.
*) How the files are collated, depends on how the file itself is named and what kind of build tags are present inside it.
For a deeper understanding of how this works, refer to the build docs.
No, you're not "supposed to put this in my GOROOT". You're supposed to execute
$ go get github.com/jcelliott/lumber
which will clone the repository into $GOPATH/src/github.com/jcelliott/lumber. Then you can use the package by importing it in your code as
import "github.com/jcelliott/lumber"
About the scoping rules: Declarations and scope

Resources