I get the sense that most Go programmers use "goimports" to work around the annoyance. I have my Emacs configured to use it automatically. I never even think about imports anymore.
You haven't yet encountered clashing names?
https://golang.org/pkg/crypto/rand/
https://golang.org/pkg/math/rand/
Or?
https://golang.org/pkg/text/template/
https://golang.org/pkg/html/template/
goimports is wonderful, but some care is needed to make sure it has added the one you intended to add.
NB: Only an issue when new imports are added, not an issue if the correct package is already referenced.
It just finds a match and goes with it, and that does cause issue. Both of the above have potential security implications.
Filippo suggests preferring crypto/rand over math/rand as a softfix in this twitter conversation: https://twitter.com/filosottile/status/752210041709719552
I'd probably prefer html/template over text/template as it's better to have someone ask why their output was HTML escaped than to have someone render HTML in plain text without explicitly wanting to do so.
If you don't think of imports anymore, how can they save you from bugs?
(I do (somewhat) understand the "more importantly, the use requirement for variables" part, but also there, I think a warning should be sufficient. Your editor could/should color-code dead code, anyways, making it stand out before you compile)
The requirement that packages aren't used isn't to prevent bugs, it's to prevent packages from claiming spurious dependencies that you're then too afraid to remove. Or, in the case of a static language like Go, don't want to take the time to remove one-by-one and see if the compilation breaks. I deal with this problem in Perl where, basically, in a source code base that's been developed now for over a decade you have no idea whether a given module is actually used in the code, and it could be pulling in a whole bunch of other stuff very confusingly. The problem is less acute in Go to start with, but it's still nice to be able to rely on the imports being accurate.
I don't think I misquoted the OP. He said "A and B help me with C" and I questioned how A could help with C, given the other claim that the OP doesn't pay any attention to A anymore.
"Or, in the case of a static language like Go, don't want to take the time to remove one-by-one and see if the compilation breaks"
That is a problem with perl, a language whose 'grammar' is about as free-form as it gets (aside: iOS is funny at autocorrecting programming language names: cobol => cool, perl => peril or pearl, depending on context), but not with go. The compiler can generate errors for unused imports; it easily could generate warnings instead.
I like clean code, but I also like it if a quick experiment doesn't require extra tooling to remove imports to make things compile, more so if it is not guaranteed that undoing such changes can be automated (adding imports isn't 100% reliable; if it were, why have import statements at all?)
In summary: Go is too opiniated here for me.
Also, this requirement effectively rules out ever using go in a repl. I think that is a minus for modern programming languages.
I don't think so either. What he wrote was unclear (sorry, tptacek). I was clarifying what I'm pretty sure he meant. It's not like I've never done the same thing in writing myself.
"Also, this requirement effectively rules out ever using go in a repl. I think that is a minus for modern programming languages."
It's ruled out for a lot of other more fundamental reasons. Go is probably the most highly polished language from the 1980s.
This would be a much greater condemnation, except the sort of people who tend to frequent HN (including me!) tend to grotesquely overestimate how much most programmers are spending coming up to speed on the latest and greatest. In many contexts, a "really nicely polished 1980s language" is a step up in either reliability or speed. Perl is nominally a more advanced language, but on the whole, most programmers just use it as a sort of dynamically-typed C. I think the majority of programmers still aren't all that clear on what a "map" is. Arming my fellow programmers with more capabilities doesn't solve any problem either I or they have, but can make them worse.
Also, I'd observe that even for modern programming languages, "needs a REPL" is setting the bar high. Rust will probably never have a REPL. I see a couple of defunct projects trying and I haven't studied them, but at best Rust could have an all-in-unsafe REPL dialect, because who's going to be able to reliably type borrow-safe code into the REPL on the first try?
And thanks for the relativism in that remark about the most highly polished language from the 1980s. I fear you are right in that (example: today, a colleague said this was the first time he created a thread. He has had a job as a developer for a few years, and, given his age, likely never wrote for a CPU that isn't multi-core. Luckily, he isn't dumb, as he asked what would happen if that thread threw an exception)
I think ML pretty objectively takes that crown, semantically speaking. For simplicity and elegance it's pretty difficult to beat.
Highlighting dead code is not a trivial matter, at least for anything that could be referenced external to the module.
But it only solves the unused imports issue. During development (especially when playing with code) I often need to temporarily comment out a section of code. I go build, and the situation usually unfolds like this: - ERROR! Yes, now, I have an unused variable dangling around, because this code was using it. - No problem, let's go on and comment out that variable as well. - Oh noes! That variable was defined using two other variables which are now unused! - The first one comes from a function result, but I still want to call that function, so I need to actually change (not comment out) the calling line to use an underscore. - The second is a global variable which using another variable? Where is it going to end?
At this point I end up following the FAQ's advice and just add the line "_ = unusedVariable". The only problem I have with that is that wasn't all this unused variables thing meant to keep us from shipping code with useless bits we don't need in production? Now I actually might end up not using this variable, but because I've ended up adding "_ = unusedVariable" during my debugging and left that on, I have no way of knowing that.
What people are arguing about is errors vs. warnings.
> things that can really cause bugs
"can" means that they don't always cause bugs: other compilers treat such uncertainties as warnings because the human looking at the screen is the one who is in charge.
Go allows you to compile code which does not respect "go fmt", why? aren't you afraid of committing working code that does not abide to the proper style? Improper formatting can lead to confusion, bugs and maintenance problems too, after all.
That has significant value, and is why I've conclude Go's choice here was the right one, despite the annoyances it causes.
I like gofmt, but I don't really care whether the compiler enforces it. It's unlikely to catch bugs.
A sufficiently bureaucratic compiler.
So how is it better than C where you get a warning (at least from GCC) that you have unused variables? You can quickly test things and you are coming back to fix all the warnings later anyway.
It's not as easy to do with a compiled language, of course, but I don't think it would be over the top to have the compiler exit with a non-success code if there are warnings when building.
The "warning fatigue" you get from C is because the warnings are either about false positives or about things that are too trivial to bother with, not because of a property inherent in compiler warnings themselves.
The problem is that while you do that, essentially no-one else on the planet does — and anyone who uses a library thus has to deal with the fact that that library has approximately a 100% chance of having nits like unused variables.
Also, if goimports solves import issues, why isn't it just built into the compiler?
Go eliminates an entire class of bugs with this feature. It doesn't just make them detectable and less likely. It eliminates them. If you don't care about eliminating them then Go's philosophy isn't for you.
But I for one am sold on that philosophy. I'm disciplined enough that in my rust code I ensure all warnings are fixed before I release. But I don't know if everyone else is just as disciplined. For Go code I do. Every library I use in Go has an entire class of bugs that are impossible. That's a useful guarantee in my book.
On a side note why do we as developers tend to prioritize making the act of writing code easier than the far more frequent act of maintaining that code? Optimizing writing you code over reading and maintaining that code long term seems like a case of premature optimization to me. Allowing something like warnings is one of those things that adds overhead to writing code but eliminates overhead over the life of maintaining that code. The gains are higher longer term at the expense of a shorter term pain. And a pain that tooling like goimports can almost completely eliminate in almost all cases.
Different phases of the development process call for different priorities: in early dev, you want reduced friction and quick turn-around time (something that the unsed imports and variables errors in Go infringe upon). Later on, you want maintainability and ensure that things don't randomly break (at this point, those errors become quite desirable). We shouldn't emphasize readers over writers all the time, we should emphasize them when it's the correct time to do so, which I'll admit is the majority of the time.
> Optimizing writing you code over reading and maintaining that code long term seems like a case of premature optimization to me.
That's actually something I've been thinking about quite a bit in the past few weeks :) I think if we were really concerned about readability of code, we would have much better literate programming tools (e.g., better integration with existing dev tools) and our programs would be written with the intent of being read by others. How many times have we felt lost in a foreign code base (or worse, a code base we wrote, but don't remember too well) trying to implement a change and not knowing or understanding some of the design decisions, being unaware of key assumptions, etc. There is a lot more to readability and understandability than having functions without unused locals. (By the way, why is it okay for a function to have unused input parameters?)
(By the way, why is it okay for a function to have
unused input parameters?)
That's caused by Go's interfaces and function type signatures. It may be necessary for a method or function to accept certain arguments to satisfy an interface or type signature even when those arguments don't get used. It's a bit of a wort I agree.The amount of development time I save by allowing warnings temporarily when testing easily outweighs any benefit to the ecosystem derived from making that warning abort compilation. I was partially responsible for making this a warning instead of a hard error in Rust and this wasn't even close to a tough call. I would be surprised if a single project in the ecosystem has ever benefited from this: projects that care about software quality pay attention to warnings, and those that don't care about this minimum standard of quality are going to be full of so many other bugs that the unused variable/import warning will make no difference.
> Go eliminates an entire class of bugs with this feature. It doesn't just make them detectable and less likely. It eliminates them. If you don't care about eliminating them then Go's philosophy isn't for you.
Go's philosophy is not about eliminating bugs above all else. If it were, then for example zero values wouldn't exist, reading from a nil map would panic, constants would have stronger types, all fields would have to be supplied when initializing structs, init ordering wouldn't be undefined, overflow would trap, errors would be required to be handled, and that's just off the top of my head.
I use Sublime Text 3 with GoSublime and have noticed that the undo stack is just my changes (makes sense, the goimports is an external process), but that's cool because any CTRL+S is going to trigger goimports and so the correction of the imports is invisible and always there.
Take a look at this adaptation of a keynote talk on the design of Go, with the title "Language Design in the Service of Software Engineering": http://talks.golang.org/2012/splash.article Section 7, "Dependencies in Go" addresses this issue: http://talks.golang.org/2012/splash.article#TOC_7. The relevant paragraph states,
The first step to making Go scale, dependency-wise, is that the language defines that unused dependencies are a compile-time error (not a warning, an error). If the source file imports a package it does not use, the program will not compile. This guarantees by construction that the dependency tree for any Go program is precise, that it has no extraneous edges. That, in turn, guarantees that no extra code will be compiled when building the program, which minimizes compilation time.
Further, the talk justifies this approach through their analysis of how their C++ codebase was compiled:
The construction of a single C++ binary at Google can open and read hundreds of individual header files tens of thousands of times. In 2007, build engineers at Google instrumented the compilation of a major Google binary. The file contained about two thousand files that, if simply concatenated together, totaled 4.2 megabytes. By the time the #includes had been expanded, over 8 gigabytes were being delivered to the input of the compiler, a blow-up of 2000 bytes for every C++ source byte.
As another data point, in 2003 Google's build system was moved from a single Makefile to a per-directory design with better-managed, more explicit dependencies. A typical binary shrank about 40% in file size, just from having more accurate dependencies recorded. Even so, the properties of C++ (or C for that matter) make it impractical to verify those dependencies automatically, and today we still do not have an accurate understanding of the dependency requirements of large Google C++ binaries.
That's a very negative way of saying "that's not my personal behavioral preference"
> There are two phases: active development and release engineering. -Wall for former, -Wextra -Werror for latter.
Many of Go's idiosyncrasies are for code readability and maintainability, which is very much a part of active development. The point being to mitigate the likelihood you end up with spaghetti code (yes, I know you ultimately end up with code quality only as good as the developer, but some languages do still make the process easier than others)
> If someone is not disciplined enough to throw out unused variables/imports/whatever from release, Go will not save him from hell.
Except it does though, since that's the very behaviour you're complaining about.
>That's a very negative way of saying "that's not my personal behavioral preference"
In my experience, Stockholm syndrome is not used to describe personal behavioral preferences, but rather (unexpected) transitions between such preferences from the negative to the positive.
In the grandparent's own words:
>>> i was shocked by that at first too. Then I came to love it.
Stockholm syndrome refers is a victim forming emotional bonding with his or her captor[1]. Which would mean in instances like this, where the "captor" is a voluntary choice of language, the term is used akin to "masochism" (albeit without the sexual element). In essence, saying "the pleasure from use feature x is derived from the pain of using feature x".
Which is why I commented that "Stockholm syndrome" is a needlessly colourful way if saying "I disagree".
No, the meaning was: if someone cannot handle unused things, that someone is screwed. Go will not save him in other aspects which require a little bit of discipline and are not checked by the compiler.
So what you're saying is, there are two kinds of people—those who don't need the feature, and those for whom the feature isn't sufficient?
My personal view on this is that warning the user should be enough. The compiler designer is basically saying: I can't trust developers to fix warnings and it is my duty to protect them from their own laziness by enforcing a certain way of working. This apparently attracts a certain kind of people. I prefer to be the one telling the compiler what to do, instead of the reverse.
I'm with you there, I just was making a snarky comment :-)
> There are two phases: active development and release
> engineering.
For you, perhaps. Go encourages you to think about your problem and develop it in the "release engineering" style from the very beginning. This is a virtue of the language, in my view.A program doesn't suffer from that. Forcing these things to be showstoppers makes sure they NEVER become a problem, and the "cost" (in terms of the developer) is pretty small in the grand scheme of things.
Adding a _ to the front of an import is not the correct way to get around this "problem" during development, commenting out the whole import is the correct way. That way if you forget, it's not in your code anywhere (as it shouldn't be since it isn't used).
The underscore system is meant only to be used when you need to import for side effects (something that i've never actually needed to use).
If you can't even agree among yourselves what is the right thing to do then I think that this is another sign that this go behaviour is not the proper solution.
If you comment out code that uses an import, comment out the import too. It's not just the recommended way, it's the only logical way of doing things.
And how is having 2 opinions on how to do something a sign that this is not the proper solution? People still can't agree on tabs vs spaces (and probably never will be able to), that doesn't mean that all programming isn't a proper solution. There are also people that think using version control is a bad idea, but that doesn't mean that all version control is broken...
So here's a language feature that you don't like. Other people don't like it and then, after they get more experience, decide they like it after all. And you call it Stockholm syndrome? By saying that, you're asserting that there is no possibility that the feature could possibly be anything other than harmful. That's... pretty arrogant, actually. Both the language designers and the users who like it are objectively wrong, and you're right?
Look, you don't like it. That's fine. It doesn't work with the way you like to develop. That's fine, too. But your assertion is that it is worse than useless for all users, and that's a bit more than you have the knowledge to assert.
The end result of Go's opinion on warnings is that you know a certain class of bugs in not present anywhere in both your code and all of your dependencies. While it's true that people and teams that follow the best practices around warnings also tend to follow the best practices for other things but there is no guarantee for the ecosystem in a language that allows warnings, and no project lives in a vacuum.
The Go compiler could simply include a bit in the resulting binary/library that indicates whether or not it was built with the "disable-unused-variable-error" flag. If you're using a library that was built with that flag the compiler can simply refuse to compile your code without that flag, forcing you to acknowledge the problem head-on.
The result will be that everyone compiles with that flag on so they can use the libraries they want/need. It's in fact actively worse than just allowing warnings. At least if you allow warnings that way you aren't forced to lower your own codes protection just because one of your dependencies does.
For example, most JS linters do that check and as a general rule, the build servers would reject the commit when the linter complains. I actually have a (very hacky) plugin to ESLint that automatically removes unused variables before `hg push`. It's totally not optimal, as in, you can still run/compile/transpile/whateverify the code with default options, but a language with no backwards compatibility worries can just add a flag to override strict checks to make a developers life easier, can't it?
I understand not implementing something that perhaps may not fit the language well or is so complicated that it really needs a lot of thought (read: generics). But this decision seems to be dogmatic at best.
I have the exact love/hate relationship with Go as the author of the article.
One under-appreciated consequence is that this policy limits Go to one implementation. Say I write an alternative implementation of Go, that has a different "unreachable code" detector. If I issue errors on new cases, then I'm incompatible with lots of existing Go code. If I fail to issue errors, then code developed against me may be incompatible with the standard Go. The effect is to suppress alternative implementations.
Better to just put my smarts into a linter, which is then just reinventing compiler warnings under a different guise.
I already mentioned that case. To be more clear: Let it not build with default options. Make it not `go get`able.
Let me develop first, and not force me to optimize prematurely.
I'd argue that cleaning unused code as you work isn't optimisation. It's a part of the refactoring process of development which is something that must happen during the main development phase.
But arguments for and against aside, most developers don't see these kinds of compiler errors that often as you'd generally be commenting out unwanted code while you're prototyping. The biggest annoyance is easily the imports and pragmatically that still takes up such an insignificant amount of effort when compared with the overall time spent writing code in any particular language. Which is why many Go advocates are willing to put up with it.
How is it refactoring if my code never builds in the first place?
> pragmatically that still takes up such an insignificant amount of effort when compared with the overall time spent writing code in any particular language. Which is why many Go advocates are willing to put up with it.
It's not a time problem. It's a focus problem. I'm working on something and then out of nowhere, receive compilation errors, which aren't urgent at all, but they distract me anyway. Even if this were indeed a very small problem, I still don't see why something most people see as a problem is pushed down the developers throat with false, dogmatic reasoning. Don't get me wrong: I have huge respect to the people who created go. I just don't like when people defend all the choices they made as "one true way".
Why would you be typing in imports that you've never used? I guess that could happen, but the more likely scenario you had used them at some point, even if just briefly, and then you're refactoring the code.
> It's not a time problem. It's a focus problem. I'm working on something and then out of nowhere, receive compilation errors, [...] pushed down the developers throat with false, dogmatic reasoning
Please don't be so melodramatic. It doesn't happen "out of nowhere" - you've purposely requested the compiler runs. And if you're compiling then you're doing so to either test your code compiles or test it runs - in either case your focus has already intentionally shifted from writing code to testing and debugging it.
> Don't get me wrong: I have huge respect to the people who created go. I just don't like when people defend all the choices they made as "one true way".
I'm not defending it. I'm saying people are being melodramatic about the actual inconvenience it causes. In all of the years I've been writing Go, I think I've spent just as much time coding around that annoyance than I've spent in this thread chatting about it. The difference being, occasionally that annoyance is useful where as the internet arguments about it literally serves no benefit to anyone.
No, I'm compiling to see if my changes still allow the tests to pass. This is a huge problem if you're doing TDD. The main argument you make is that it's not such a big problem and I think the number of people complaining says otherwise. Or maybe we developers just like being melodramatic. I honestly can't tell. Maybe what triggers such passion is go being very close to a perfect tool for certain things and those annoyances look like small black dots in a perfectly white surface (That sounded dramatic as well, what's wrong with me? :) )
Isn't it implied that programmers are adults?
I can't say I blame Rob Pike for not trusting developers, and I've definitely seen more than one case of a C/C++ codebase riddled with thousands of compiler warnings that were just ignored en masse during compilation.
There is another side of the coin, which is that experienced and disciplined developers who think they can take care of themselves, thankyouverymuch, would end up feeling limited by Go.
It's one of those irregular situations:
I'm a senior developer.
You're an adult programmer.
He's a stark raving juvenile lunatic.
The point about alternative implementations is interesting. Java has a comparable situation with unreachable code; the language specification has a simplistic definition of what unreachable code is, and makes it a compile-time error. A smart compiler can find more cases of unreachable code, but isn't allowed to make them errors. So it makes them warnings. It doesn't seem to be a big impediment to alternative implementations in practice.
There is a cost to this too. It is another option. Another thing to document and maintain. Another thing for developers to learn about. Another thing for newbies to be confused by. Another thing that will asked about on the mailing list.
Also doesn't that workaround completely nullify all the arguments they made in that section? And it puts the programmer in a worse position than if they could just turn it off temporarily.
The answer to this and a lot of similar such questions about Go is "scale". Things that were sorta kinda convenient for you in a couple hundred lines become nightmares when several dozen developers on several hundred thousands lines of codes had differing ideas of what was convenient for them at the time.
Just as you can't understand Erlang until you understand its emphasis on reliability, you can't understand Go until you understand its emphasis on coding at scale. Almost (but not quite) everything people can't understand about Go are things that people want to do because they work well locally, but things that have become serious problems in source code bases at scale. You also can't understand Go until you realize that the problems weren't merely hypothesized, but extracted from real already-existing source code bases.
That said, I still feel they missed some steps. I'd like non-nil-able pointers. (Optional, like C#, because the way Go methods work means that if you're careful nil pointers of a certain type are perfectly legal and can have sensible methods on them, but that's not always the case.) Packaging is another obvious case where Google had an answer that worked for them so they didn't see a problem, though that's being worked on. (I'm struggling through this because I consider it a non-negotiable feature that my packaging solution allows me to locally mirror everything I use, which all packaging systems (not just Go!) seem to consider some bizarre use case. Strange, I consider it a basic requirement for truly professional development.) So bear in mind I don't mean this necessarily as a defense of Go, I'm talking about what it takes to understand it.
(Edit: also, yes, I consider it a bit sad that Go doesn't have iterator support, per my comment at https://news.ycombinator.com/item?id=12210351 You can sort of bash some stuff together, and io.Writer and io.Reader cover a common case for Go programs and can be composed, but it's still a bummer.)
It is completely the case that some people will come to a greater understanding of Go, and realize it's the wrong choice for their problems. But perhaps it will, at the very least, be less threatening that other people do consider it a good choice for their problems.
In that world, this sort of thing enforced strongly makes me much happier.
For random one-off hacking, yea, it'd be a pain.
Differing use cases lend cause to different tooling.
> Differing use cases lend cause to different tooling.
What?
If you're messing around with your own test code, it's fine if your compiles get slower, etc. On the other hand, if you're writing code that thousands of other engineers are immediately going to depend on, it's better if you're not allowed at all to make things slower via unused imports. True, if you could globally mandate the use of a lint/presubmit rule disallowing unused imports, that would also work. But, that's a harder swing.
I am not writing code that thousands of other engineers are going to depend on. A company that requires this can enforce methodological rules. Go is supposed to be used in different contexts, not just Google, right?
> What?
Different needs, different languages.
I write 100-line scripts in Perl that rip apart text files and extract the bits I want. I don't write 100,000 line embedded systems in Perl.
So, if you're complaining that a language doesn't satisfy a need well, then go find one that satisfies it better. Use that instead.
Anyone using a modern IDE pretty much never even thinks about imports, which are (and should be) automatically managed by the tool, not by the programmer.
In this particular case, the IDE could automatically remove the imports when you remove the corresponding symbol from your source, or automatically add the import when you introduce a new symbol.
The "can be supplied by any external tool" is a cop out that was acceptable in the 20th century but this is 2016, we have a higher bar for developer productivity.
No, they're not.
There are a few necessary conditions for this kind of symbiosis to work well:
- The language has to be statically typed. Without type information, the IDE is completely blind and can barely help you at all without human supervision.
- The IDE has to be written on top of the same runtime as the language it's editing. This is what makes Eclipse/IDEA and Visual Studio so spectacular: they understand the bytecode they are working with.
These are necessary conditions but they're not sufficient. You can still write crappy IDE's if these conditions are met, but thankfully, IDEA/Eclipse/Visual Studio are technical wonders that multiply the productivity of their users.
For example, in Go, the simple action of selecting the the surrounding expression simply doesn't exist anywhere. It's the most basic automatic action that's trivial to do with the proper language and IDE, and yet nonexistent in Go. Along with tens of others.
That's the price to pay when a language is designed without any consideration for its tooling nor basic things we learned about language design these past twenty years.
Go is statically typed.
> the simple action of selecting the the surrounding expression simply doesn't exist anywhere
How so? It's trivial with the `go/ast` package.
var _ = unusedImport
Or use goimports. Then you don't even have to think about it.
> var _ = unusedImport
This is what the devs suggest as an alternative to having a compiler flag to turn off the check.
But with a compiler flag, I can easily discover the unused import when I build for production, simply by turning that flag off. By using the variable in a dummy way, I need to remember to go back and check for such things.
Presenting this as a way to address the problem feels like it's missing the point.
>I'm glad there are not such compiler flags.
Because if they were there people would force you to use them? Or are you just unhappy that people could have a different debugging workflow than you?
You can fork it and set it to only remove unused imports. In fact I've done just that few days ago but for different reasons(i.e. I generate some small programs and I use goimports as a quick and dirty way to to clean-up the unused imports). Here is the line where you need to return https://github.com/golang/tools/blob/master/imports/fix.go#L...
> Because if they were there people would force you to use them? Or are you just unhappy that people could have a different debugging workflow than you?
Yeah, I don't want being forced to use a dozen of flags just to compile a hello world program. Nor I do what to see various warnings that nobody really care about. It should fail or succeed. I prefer basic/minimal API that I can build upon not a kitchen sink approach. I think that's what makes Go a great ecosystem compared with many others. Compare the current Go compiler with various C++ compilers and you understand what I mean.
To sum it up you may use separate tools to do various magic things (i.e. goimports), they do not need to obey the Go1 compatibility rules. The issue is not that big to warrant a compiler flag.
This seems like it removes half the value of the tool, though. I can comment out a line of code, compile and test the program. But if I uncomment that line, I'm now missing an import.
edit- how does a tool like this sound?
* If it sees an unused import, it comments it out
* If it sees an import is needed, and there's a commented-out import which would fit, it uncomments it.
* It can run in a "check for commented-out imports" mode, so that commit hooks can reject such a state.
I guess (making some assumptions about go's import semantics) this would avoid the ambiguous name problem; it would mean you avoid having to edit both the import and the usage at the same time; and it makes it easy to tell if a file should be cleaned up.
Maybe it would cause issues if you're trying to choose between two libraries which both provide the same symbols?
Can't agree with that. We once had an issue with our code because someone had made a copy of his code base and goimports was importing an older version of a library.
Yes definitely this is something the programmer could have prevented. BUT! "not think about it" is not really true.
import _ "unused/package"
This is usually used to benefit from the packages' side-effects (e.g. trigger init() - mostly used in SQL drivers to register the driver).If you want to explicitly import unused packages, you just prefix it with `_`, like this: https://play.golang.org/p/ltfQgco22t
Remove the `_` in the import of `crypto/rand`, and the program won't compile anymore.
That can be a bit annoying, but it's not terrible. Back when Go had insanely great compile times, it was worth it. Now that compile times are … okay … it's — okay.
Basically, as soon as I save my file, it gets formatted, linted, unused imports are removed, the project is then compiled and unit tests are ran. I couldn't be happier.
The fact that there is not a compiler flag to disable this behavior, and that the core team is opposed to adding such a flag (https://golang.org/doc/faq#unused_variables_and_imports), is simply ridiculous and makes programming in Go a real pain in the ass.
I can't think of any other language that does this.