As I come from a C and C++ background and golang is semantically different I have some discussions about function names "New" vs "Open" and what the programmer expects what to happen under the hood. I have created a package where the New function opens file descriptors to temporary files. I'm not sure this is intended behavior for APIs written in Go.
Here is a snippet:
// Not directly convenient New allocates file descriptors
deb := New()
deb.AddFile("/tmp/myfile")
deb.Write("/tmp/mypackage.deb")
deb.Close()
// Idiomatic it opens file descriptors but we have to provide context to open
info := &Props{Name: "mypackage"}
deb := info.Open("/tmp/mypackage.deb")
deb.AddFile("/tmp/myfile")
deb.Close()
Go's community is still finding its idioms and patterns, so don't consider anything dogma. Based on what I've seen in a year and a half, I don't think it's wrong to touch disk in a New function if it has godoc comments explaining the behavior. It would be unusual, and probably make more sense to touch the disk in d.Write(). Some common patterns I've seen with New functions:
are only exported when designed for use by other packages
makes sense when invoked from other packages with the package name prefixed: d := deb.New(...) (since you have a variable named deb, your package is something else)
returns an instance of the package's main business logic, to be used further
accept dependencies as arguments instead of constructing its own dependencies (hopefully any behavioral dependencies are interfaces)
often a main() function assembles those dependencies, calls d := deb.New(deps), and executes the behavior d.AddFile(); d.Write(); d.Close()
an example signature using an interface:
package deb
// New accepts blah returning a *Deb. It returns nil if blah.
func New(name string, to io.WriteCloser) *Deb {...}
Related
There's a lot of examples in test code that are shadowing package names in test libraries like testify.
For example:
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSomething(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
var a string = "Hello"
var b string = "Hello"
assert.Equal(a, b, "The two words should be the same.")
}
Shouldn't it be an explicit decision and rare occurrence to override the value of a package namespace with a local variable?
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSomething(t *testing.T) {
assertions := assert.New(t)
req := require.New(t)
var a string = "Hello"
var b string = "Hello"
assert.Equal(a, b, "The two words should be the same.")
}
I'd expect the proper behavior to be aliasing the package like pkgassert which I doesn't feel idiomatic, or ensuring that variables are not set to the same name as the package: assertions := assert.New(t).
Other examples:
Ok: buf := bytes.Buffer{}
Bad: bytes := bytes.Buffer{}
Note: I'm not focused on variable naming patterns, as Go tends to recommend single letter, or short variables in the narrowed scope you might use the buffer for. Assume the longer name is acceptable and desired due to the function length.
If this is a desired behavior in testing packages I'd like to know why?
It appears to violate a key principle of idiomatic Go in "no magic" and being readable.
If there are undesired side effects from this I'd like to know of that as well.
My assumption is that is means after import that any calls to the package in the same scope wouldn't work due to variable shadowing
Edit
Scope Shadowing in Go was a nice read and gave some great points on usage. The main takeaway I had from this and from Stack commenters:
It can enhance readability. (I think this is probably due to Go preferring small concise naming for packages, making package names in Go variable length.)
Parallel Test Issues was something I recall reading a while back. I didn't understand the recommendation to "hide" the loop variable by putting in:
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Here you test tc.value against a test function.
// Let's use t.Log as our test function :-)
t.Log(tc.value)
})
}
}
With a better understanding of shadowing, I'm seeing this "hiding" was talking about shadowing the caller scope variable of tc by assigning inside the loop, thereby shadowing.
This seems like a good use case, though I still feel it is being "clever" rather if not commented, and violates the idiomatic Go goals of being clear and readable with no "magic".
After reviewing all the feedback and writing I've seen I'm going to summarize the findings here.
If you are investigating this behavior after seeing Go linting alerts from a tool like Goland, hopefully this answer will save you same time and make clear that it's ok, idiomatic, and only in some cases of reusing the actual package calls after initializing would any issues be experienced.
Shadowing Package Names With Local Variables
This is a matter of opinion, there is no official statement indicating this is considered non-idiomatic code.
Opinions seem to overall lean towards avoiding shadowing unless intentionally done for clarity & readability, but this is again opinion, not a requirement.
Once overridden, the package would be unavailable in that scope as the package name has been shadowed by the local variable.
I've observed that this behavior seems more likely in Go than some languages, because Go prompts package names that are short, not multi-word, and easy to type. It seems inevitable that assert := assert.New(t) could result when this happens.
Consistency, as always in matters like this, is the key. If a team determines to never shadow the package name, then assertions := assert.New(t) could be used, or as mentioned the package could be aliased such as import tassert "github.com/stretchr/testify/assert". This is an opinion standard, and either way is legal and considered idiomatic.
In the case of testing, this is commonly done as further usage of the package after the initial variable set isn't used further. Example below using the is is package. Package author comment on this (again this is opinionated, but it doesn't break anything to use it with is := is.New(t).
package package_test
import (
"testing"
"package"
iz "github.com/matryer/is"
)
func TestFuncName(t *testing.T) {
is := iz.New(t)
got := FuncName()
want := ""
is.Equal(got,want) // AssertMessage
}
Shadowing Behavior Can Address Goroutine Variable Issues
Shadowing is a known behavior and documented clearly in Effective Go.
The bug is that in a Go for loop, the loop variable is reused for each iteration, so the req variable is shared across all goroutines. That's not what we want.
It may seem odd to write req := req but it's legal and idiomatic in Go to do this. You get a fresh version of the variable with the same name, deliberately shadowing the loop variable locally but unique to each goroutine.
This can be solved without shadowing by passing in the variable as a parameter into the embedded func as well, simplifying the code. Both are legal and considered idiomatic per the guide.
Shadowing for Tests
Related to this goroutine behavior, but in the context of a testing, parallel tests run in goroutines, and therefore benefit from this pattern as well.
The tc := tc statement is required in the parallel test example because the closure runs in a goroutine. More generally, the tc := tc idiom used in the context of closures where the closure can be executed after the start of the next loop iteration - credit #gopher in comments
The gist on Be Careful With Table Driven Tests mentions this behavior as well in the How To Solve This.
Detecting
The check go vet can check for shadowing, but is not considered part of the stable package, and was removed here related to GitHub Issue 29260 and GitHub Issue 34053.
The change seems to have been prompted for compatibility purposes due to the requirement of unsafeptr flag. Additional comments seem to point towards also requiring better heuristics before allowing in go vet without being experimental.
Go Vet Shadow
Instructions on running via go vet: Package Variables With Instructions:
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)
For those wanting to lint this, golangci-lint does have an option to configure shadowing checks in the configuration (search for check-shadowing as no bookmark to that text block`.
Further Reading
Scope and Shadowing in Go
Scopes and Closures
Wow, that is awful code. While it might not be a compiler enforced rule, if I see this:
import "github.com/stretchr/testify/assert"
Then in that file, as far as I'm concerned, any identifier spelled assert is the top level import from that package, period. Anyone who breaks that pattern, in the name of being "clever" or whatever, is just asking for trouble. People's muscle memory is trained to recognize top level imports, so please, do not do stuff like this. If you want to avoid thinking of a new name, just remove some letters:
asrt := assert.New(t)
or add a letter:
nAssert := assert.New(t)
or alias the import:
import tAssert "github.com/stretchr/testify/assert"
Just please, do not follow the poor example given in that code.
I have been doing a bit of go programming of late and while trying to follow Effective Go style guidelines, I sometimes find it difficult to avoid stuttering when naming packages and interfaces and structs.
As an example.
I might have a console package with a Console.go file containing a Console interface a console struct and a New function.
//console/Console.go
package console
type Console interface {
Print(s String)
}
type console struct {
....
}
func (c *console) Print(s String){
....
}
func New() Console{
return &console{}
}
Now when I use this somewhere I end up using a console.Console type everywhere.
When I have two or more structs in a package I end up things like
con := console.NewConsole()
I don't mind having large mostly flat package structures but I do like to keep my code organized as much as possible. I am ok with the idea of IO.Reader and IO.Writer but what to do when the package is the same as the thing but still needs to be separated. (Yes I am aware that the given example could be Console.Writer but lets pretend its something completely different)
So my questions are:
Is this stutter effect something I should even worry about? (ie. Is it bad form?)
Does anyone have any tips in avoiding it?
Stuttering type names are generally fine - it's not unusual to have a foo.Foo, because package foo is dedicated to defining type Foo. There's absolutely nothing wrong with that.
What you want to avoid is unnecessary stuttering; this would be things like foo.NewFoo when simply foo.New is sufficiently precise, or foo.FooBar and foo.FooBaz where foo.Bar and foo.Baz would work just as well.
Consider the standard library's html/template, which defines a type (template.Template) and a constructor (template.New).
I am currently writing ExampleFuncs in my Go test scripts. For example:
package hello
import "testing"
func ExampleGetSymbol() {
data := GetSymbol("AAPL")
fmt.Println(len(data.Data))
// Output: 21
}
Now, this gives me two benefits:
This example is executed when I am running go test and
It appears in the godoc documentation under func GetSymbol
One thing bothers me and I am wondering if there is anything I should do about it.
For the user that's trying to learn from this example, the line
data := GetSymbol("AAPL")
should actually be
data := hello.GetSymbol("AAPL")
but since the test is in the same scope as the package, I cannot use it like this.
So I guess the distilled version of my question would be:
Is there a way to allow package.field notation inside the package scope?
Thanks in advance
Rather than putting this in package hello, put it in package hello_test. You're allowed to have both hello and hello_test packages in the same directory, and it allows (requires) you to create your examples the way you're suggesting.
Incidentally, this also causes you to write your test cases (at least for this file) only to the public API. This is often a good thing. But if you need to write to private functions, you can split your tests into separate files, some in the hello package and some in hello_test.
BTW, documentation for this is slightly buried. You can find it in the "Test packages" section of the go cmd documentation.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
From looking at a lot of Go code on GitHub, I have noticed that Go coders love the short variable declaration (:=)and use it very often. Here's an example Coding Style. But this usage seems far too often to create poorly structured code: Very long functions that bundle lots of functionality together, because Short variable declarations may appear only inside functions. If you want to set up a package that encapsulates something akin to a class with members that several short, modularized functions operate on, as good structured programming and OOP practices mandate, you can't really use short variable declarations effectively for member variables. I tend to get uneasy whenever I see any function that's more than 10 or 15 lines long - I know something's probably not right with that design.
Personally, I'm not a big fan of short variable declarations except for local initializion of loop counters, etc. Aside from the above mentioned issue, I like to see clearly the type I'm working with. Particularly when looking over new code, short variable declarations assume that the reader knows what the function initializing the variable is returning, or obliges them to go and find out, or deduce it from the context. So, that code becomes less readable and requires the reader to stop, and perhaps search somewhere for its meaning, whereas avardeclaration might make things immediately clear.
(I suppose one way write better code and still use short variable declarations would be to avoid the use of package global members entirely and parameterize all your functions - not necessarily a bad thing - but this probably creates more work than you will save using short variable declarations.)
As a result I have been opting to use this sort of design for my packages, similar to the way declaration and initialization work in traditional OOP languages such as Delphi and C++:
package myPackage
import (
"importA"
"importB"
)
var m_member1 *importA.T
var m_member2 *importB.T
func init() {
m_member1 = new(importA.T)
m_member2 = new(importB.T)
}
Then I have clearly typed, initialized and encapsulated package members that are available for use in the package. Yes, this does violate the good practice of initializing only when necessary, but I don't have to do this in init() either - can do it on an as needed basis, when the member is used for the first time, although that has other potential complications. (Be that as it may, since initialization of class members in a constructor has been common practice for a long time, I don't have much of problem with this, regardless.)
Is this non-idiomatic, "bad" code in Go? Is the abundant use of short variable declarations, with their IMO negative consequences, considered a good thing? Frankly I fail to see how it could be. I tend to think that perhaps short variable declarations are being used too much by programmers who just love the short syntax, and the result is a lot of bloated looking spaghetti style code. Am I missing something?
Edit: Since the question as stated caused a good deal of confusion, I'll try to illustrate with a simple example (this may or may not compile - wrote quickly just to illustrate)
If I write:
package main
import
(
"packageA"
"packageB"
)
func DoStuff(){
a:=PackageA.T
a.Dostuff()
}
Then it will be very easy to continue and write:
func doStuff(){
a:=PackageA.T
b:=PackageB.T
Dostuff(a)
DoMorestuff(b)
DoEvenMorestuff(a,b)
DoLotsofstuff(a,b)
.....
}
func main(){
DoStuff()
}
IMO bundled, bloated, poorly structured code.
______________________
But when I write
package main
import
( "packageA"
"packageB"
)
var a packageA.T
var b packageB.T
init(){
a=new(packageA.T)
b=new(packageB.T)
}
Then I can write:
func dostuff(){
a.Write()
}
func doMorestuff(){
b.Write()
}
func doEvenMorestuff(){
a.Read(b)
}
func doLotsofstuff(){
a.ReadWrite(a,b)
b.WriteRead(b,a)
}
func main(){
dostuff()
doMorestuff()
doEvenMorestuff()
doLotsofstuff()
}
A modularized pipeline style design, which cannot be implemented with the short variable declaration form. The best that can be done using the short form is nested, parameterized functions, which are generally not a very good design choice either.
Some complained that this amounts to globals, but in a well designed, encapsulated package with a minimal public interface, that is no more of an issue than declaring variables local to a function. Packages should be atomic. Member variables have been an accepted component of OOP design "forever" and when used properly, following the rules of OOP and structured programming, they are not globals, but locals to the package or module or class which encapsulates them.
Granted, there is no feature of any language that cannot be used, or abused. My question is simply that short variable declarations seem to be ripe for abuse and force certain design decisions that are less than desirable, unless used very discreetly. I'm asking if there is a way to use the form that will circumvent the issues I have with them and afford me their ease of use without the drawbacks.
Edit 2:
Perhaps this is something of a compromise:
package main
import
(
"packageA"
"packageB"
)
func dostuff(a PackageA.T){
a.Write()
}
func doMorestuff( b PackageB.T ){
b.Write()
}
func doEvenMorestuff(a a PackageA.T, b PackageB.T ){
a.Read(b)
}
func doLotsofstuff(a a PackageA.T, b PackageB.T ){
a.ReadWrite(a,b)
b.WriteRead(b,a)
}
func doStackofStuff(){
a:=PackageA.T
b:=PackageB.T
dostuff(a)
doMorestuff(b)
doEvenMorestuff(a,b)
doLotsofstuff(a,b)
}
func main(){
doStackofStuff()
}
Still bundled up in main() but that's not really a complaint - doStackofStuff() is my interface call. In "real code" I would write a separate package for all of it, and only DoStackofStuff() would be public and callable from main() - the rest would be encapsulated. The implementation is broken up in doStackofStuff(), yet using the short form without nesting.
The answer is actually very simple. The only alternative to short variable declaration e.g. a := 2 is the long variable declaration e.g. var a int = 2.
Does either of them promote spaghetti code or make functions inherently longer? No.
I think you are mixing a few issues here that are not connected:
If you need to emulate classes and structs in Go - don't use modules for them. Use structs. Build "constructors" for them. That's it. I'd hardly even call it emulation, even though it's not 100% identical to C++ or Java classes. I mean, why not just do something like
type Foo struct {
Bar string
Baz int
}
func NewFoo(bar string, baz int) *Foo {
return &Foo{
bar,
baz,
}
}
//and if you want static state - just do this
var DefaultFoo *Foo
func init() {
DefaultFoo = NewFoo("foo", 1)
}
I don't fully see why doing := inside functions will create spaghetti code. Can you make your point clearer on that? The most harm it can do is scope collisions if you're not careful - like in this example:
var x int = 3
func main() {
if x == 3 {
x := 5
fmt.Println(x) // will print 5
}
fmt.Println(x) //will print 3
}
going back to your example - it's not bad design to import types from a different module (e.g. have a static http client initiated in a module's init() function). But you have to make sure you are really not mixing up responsibility between the two packages.
Where in Go's source code can I find their implementation of make.
Turns out the "code search" functionality is almost useless for such a central feature of the language, and I have no good way to determine if I should be searching for a C function, a Go function, or what.
Also in the future how do I figure out this sort of thing without resorting to asking here? (i.e.: teach me to fish)
EDIT
P.S. I already found http://golang.org/pkg/builtin/#make, but that, unlike the rest of the go packages, doesn't include a link to the source, presumably because it's somewhere deep in compiler-land.
There is no make() as such. Simply put, this is happening:
go code: make(chan int)
symbol substitution: OMAKE
symbol typechecking: OMAKECHAN
code generation: runtime·makechan
gc, which is a go flavoured C parser, parses the make call according to context (for easier type checking).
This conversion is done in cmd/compile/internal/gc/typecheck.go.
After that, depending on what symbol there is (e.g., OMAKECHAN for make(chan ...)),
the appropriate runtime call is substituted in cmd/compile/internal/gc/walk.go. In case of OMAKECHAN this would be makechan64 or makechan.
Finally, when running the code, said substituted function in pkg/runtime is called.
How do you find this
I tend to find such things mostly by imagining in which stage of the process this
particular thing may happen. In case of make, with the knowledge that there's no
definition of make in pkg/runtime (the most basic package), it has to be on compiler level
and is likely to be substituted to something else.
You then have to search the various compiler stages (gc, *g, *l) and in time you'll find
the definitions.
As a matter of fact make is a combination of different functions, implemented in Go, in the runtime.
makeslice for e.g. make([]int, 10)
makemap for e.g. make(map[string]int)
makechan for e.g. make(chan int)
The same applies for the other built-ins like append and copy.