9 ms·
Go: a nice language with an annoying personality
- kristianp 14y agoGood point about having to change the "_, err :=". I have found I have had to cascade changes to ":=" in go programs. I guess it does reduce the pythony feel.
- swdunlop 14y agoThe _, err cascade is a nuisance when refactoring; I have gotten into the habit of throwing a var err error at the top of any function with a number of possible error results -- it also makes a handy notation that "here there be glue code." Of course, where there's "_, err = ...", "if err != nil" returns are rarely far behind. :)
- NateDad 14y agoif you use the standard if _, err := foo(); err != nil { then the err variable's scope is limited to the if statement (usually correct), and you can then move that if statement where ever you want and it will stay intact, and will not interfere with the external code.
- saiko-chriskun 14y agoYeah recently just started on my first go project.. I use hopwatch for debugging and I do end up commenting/uncommenting the module import all the time :/
- BarkMore 14y agoWhen debugging, add the package-level statement var _ = fmt.Println to avoid unused errors. Here's an example: http://play.golang.org/p/cZtmILYWoZ http://play.golang.org/p/cZtmILYWoZ
- melvinmt 14y agoEven easier: just add _ before you import: import ( _ "fmt" ) To prevent the unused var error you can assign the var to an _ as well: _ = unusedVar
- sltkr 14y ago> Even easier: just add _ before you import How is that an improvement? That's just as much work as commenting the line out.
- laurent123456 14y agoI haven't used Go yet, but I think I would just stick a fmt.Print("") at the top of the function I'm debugging to make the compiler shut up.
- enneff 14y agoOr you can just declare an anonymous global variable: var _ = fmt.Println Now the fmt package is always in use. No more import issues.
- tlb 14y agoCommenting out code is ugly anyway. I think you want if 0 { fmt.Print(m) }
- DanWaterworth 14y agoThat's arguably worse than commented out code.
- beagle3 14y agoArgue then: The editor can just as easily highlight this is "unreachable/useless code" (maybe even using the comment colors). However, the compiler will check the syntax and semantics of that statement to make sure it is ok. I say it's better then commenting out code (although a #define non_executable_for_reference_only if 0 would have probably made that more readable)
- DanWaterworth 14y agoYou shouldn't add code that doesn't do anything, it just creates a cognitive burden. You might be able to relieve that burden with a clever editor, but there's a clear (and useful) dividing line between code and comments that you are blurring.
- beagle3 14y agoI disagree that it's code. It's documentation - that can be checked by the compiler for correctness. Yes, it is a hack, but it serves a purpose. It's just a matter of convention; It creates as much cognitive burden as documentation does. And indeed, I avoid documentation where it isn't needed, but I do put it where it is helpful - just like I do with code that doesn't need to be built/executed as part of the product, but that helps understanding.
- stcredzero 14y ago> It's documentation - that can be checked by the compiler for correctness. Exactly. This was a convention used by Smalltalk shops. It came about because of the appearance of the Refactoring Browser, which caused a 10X increase in the rate and ease of refactoring. Before, Smalltalkers used to put snippets of code in comments with the exhortation to "run this" or "debug this" to clarify how a certain part of the API worked. The problem arose that refactorings would often break those snippets. However, false ifTrue: ["Debug this" myObj := MyClass new. myObj myWonderfulMethod.]. ...was very fast (it was a jump on many VMs) and would never break even if refactorings hit it.
- tcoville 14y agoI have had this problem as well and of course you can add some superfluous code that fulfills the usage for the import/variable but then you have to remember to clean up that code later (essentially discarding the very helpful checking built into the compiler). I think they would be better off adding a compiler flag for less strict checking for development.
- kragen 14y agoAside from the var _ = fmt.Println trick to avoid having to comment out the module import, maybe part of the problem is that Go is aimed a little further think-ahead-ward and a little less hack-until-it-works-ward than they're used to? Because that might be on purpose.
- aston 14y agoOne solution to the fmt.Println problem is not to use it at all. There's a built in println function that works alright for debugging messages and requires no import. http://play.golang.org/p/y5XX4RDTW5 http://play.golang.org/p/y5XX4RDTW5
- afandian 14y agoThank you! I have this problem and find it immensely frustrating. Not frustrating enough to write a blog post and post it to HN. Glad they did.
- minikomi 14y agoThis is also an option: http://play.golang.org/p/qJ5vSnPzb3 http://play.golang.org/p/qJ5vSnPzb3
- swdunlop 14y agofmt.Println has better support for slices, interfaces and pointers; println is deliberately more minimal since it is a builtin.
- dougk16 14y agoThis is the kind of problem that can and arguably should be handled/eased by whatever editor or IDE you are using. A quick key combination to clear unused imports, another one to add required imports.
- egeozcan 14y agoIt works amazingly well with Visual Studio (especially with the ReSharper add-on) in practice. I've never heard anyone complain about it.
- laureny 14y agoThis kind of code clean up should be the job of IDE's, not compilers. Sadly, it looks like the Go authors have never heard of those.
- Flow 14y agoUnless code cleanup is enforced by the IDE/checkin it will not always be done. Here at work we have VS2010, TFS, Resharper and yet some developers don't care about unused imports and references. Some developers use "dark themes" and it seems they don't see all the gray code that can be cleaned up. I'd love this to be hard errors like in Go, but it's too late now.
- egeozcan 14y agoWell you have stylecop.
- Flow 14y agoYeah, but it's too late. :-/
- RHSeeger 14y agoI fail to see the draw to the argument that, because some people are bad developers, the rest of us should be handicapped. Making the worst developers better at the cost of making the better developers worse (productivity-wise) doesn't seem like a valid tradeoff unless the gain on the lower end far outweighs the loss on the upper end.
- 4ad 14y agoGo ships with a Go parser in the standard library. Among other things it is used by gofix, gofmt and go vet. People from the community have used it for writing various refactoring tools. It's incredibly useful; I don't want to go back to a language that doesn't ship with a parser in the standard library. I'd say the Go authors have thought about support for tooling much more than other language authors, not less.
- stcredzero 14y ago
- drivebyacct2 14y agoWhy do we keep upvoting these short repetitive rants about Go? There are a half a different posts with this exact same complaint. There are another dozen threads about it on the mailing list with plenty of discussion and it comes up in almost every single comment thread here. Yes, the error handling is explicit. If this is a bother panic/defer+recover is there if you want to use it. The case here is completely contrived; a red-herring. It's not like it's ever typical to do m, err := io.Read... and not use the `m` (if you were, you'd already be writing _, err anyway). Assuming that you write a block of code and then compile it and not write all of your code line-by-line and compile it... and then I guess try to artificially fix the compiler message instead of writing the code to utilize m first? edit: My only point is that this isn't even an issue that arises when normally writing code; the scenario in the blog isn't one that occurs when one sits down, writes a function and then compiles it. Sorry to whoever I upset.
- _ak 14y agoYou are totally right: in the last 2+ years I've programmed in Go, this has never been an issue. OP's example seems very contrived.
- randallsquared 14y ago> The case here is completely contrived; a red-herring. It's not like it's ever typical to do m, err := io.Read... and not use the `m` (if you were, you'd already be writing _, err anyway). I've been doing some Go recently, and I ran into this exact problem (except the rhs was something else). Ignoring the output of a not-directly-related function while debugging is quite common, in my experience. Like some others here, it didn't rise for me to the level of ranting about it, but it's interesting to see that it's not just me, so I'm glad it did for someone. :)
- notJim 14y agoIt's pretty hilarious to watch people clambering all over each other in this thread to claim this isn't a problem because [op_is_doing_it_wrong] or [weird_hacky_workaround]. Commenting out bits of code to see what effects it has is one of the most useful ways of not only debugging a program, but learning to program, and “reading” code. Just because some really smart people made a decision for reasons that are great 99% of the time, but fail badly in a very important 1% case doesn't mean you have to redefine your entire belief system to avoid criticizing them.
- bcbrown 14y agoI usually read the first couple comments on an article before reading the article itself. I was all set to write a comment disagreeing with you after reading the first couple paragraphs, but by the end I completely agreed. Sounds like it would really disturb my flow while debugging. I'm sure there's reasons it would be a bad idea, but having the ability to ignore errors like this when building a Debug build seems like it could be a solution.
- blablabla123 14y agoThere are plenty of workarounds. Anyway, like others I work full-time with Go and it has become an absolute non-issue for me. In 80% of the cases fmt is already imported, but in 99% of the cases I have a global variable log defined in every package anyway -- and if not I define it. (Working often test-driven, I avoid the issue totally by doing t.Logf.) So yes, every 2 months (I'm serious) I'm running into the OP's problem and it happens that I'm writing fmt.Printf("") -- but this almost exclusively happens on "Pastebin-projects". There is great reasoning behind the concept of providing as few exceptions as possible to the users. Sometimes it means adapting your workflow/thinking, but I guess this is the case for every language if you want to become truly productive.
- stock_toaster 14y ago> It's pretty hilarious to watch people clambering all over each other in this thread to claim this isn't a problem because [op_is_doing_it_wrong] or [weird_hacky_workaround]. "Clambering" may be a bit hyperbolic, given there are only 15 comments (at the time I read this), and a handful of those propose "weird hacky workarounds" or "op is doing it wrong" comments. Aside from that, I agree with the author that the variable not used errors are certainly irritating during a development or debug cycle. On the other hand, it is nice during a normal compile, or when using go get to pull a lib in from some other author. There are indeed numerous work arounds, using build constraints (go build tags args) and such. Many (most?) are quite hacky and not very general case or new-developer-friendly. It would indeed be nice to have a 'debug' compile flag that ignored such errors, if only for a little while. Maybe even make it only usable with "go build" and never "go get" or "go install".
- btilly 14y agoCan't you just write a debug function, that checks a variable, then either does nothing or calls fmt.Println? Set the variable from a command line parameter. Sprinkle debug statements everywhere you want, and flip the parameter as needed. Since the import is always used, it is never an error. No problem.
- stiff 14y agoThis is hardly surprising considering Go shares its creators with Plan 9 among other things. They have had this kind of attitude for years, see for example this thread where someone asks about some features in the Acme editor: http://9fans.net/archive/2008/08/134 http://9fans.net/archive/2008/08/134 "Just say no"
- krichman 14y agoIf anyone told me ,"write better code," in response to a question like, "does it have code folding?" I would be pretty enraged. I don't even use code folding.
- enneff 14y agoTo be fair, the original person was asking about the "Acme way." And the Acme way is, indeed, to just say no to a lot of the conventional wisdom about how editors should work. Go may share some of Acme's developers, but it is a very different project to Plan 9.
- jrogers65 14y agoI've noticed that software developers (and people in general), at the highest level, are split into three camps. One of them takes the "nothing really matters at all" attitude (see: the majority of PHP developers). These people do not subscribe to dogma in the least but lack structure to such an extent that everything is a mess. The next category is of the opinion that everything must be done in a certain way (the Plan 9 creators, most Java developers). This camp emphasises dogma above all else, even at the expense of common sense. The final group, which is in the minority, consists of those who are truly pragmatic while taking the ideal into account at the same time. They tend towards perfection but know that the universe is not perfect. These are the Zen masters of development.
- beagle3 14y agoI mostly agree with the sentiment, however: Most of what's built on a "nothing really matters" platform is total mess. Most of what's built on top of a "certain way" platform works and is a good foundation to build more platforms. Most of what's built on top of the "truly pragmatic" platform works, but is less often a foundation to build more platforms. We need the fanatics like RMS to jumpstart GNU, and the Plan9 people to jumpstart plan9 - a lot of what you take for granted in Linux these days like namespaces, /proc, utf-8 was copied from Plan9, and for a reason: It's easier to copy features from a clean, consistent, proven implementation like Plan9 then from an inconsistent hodgepodge like the NT kernel. (And yes, I did NT kernel programming until just about the time XP came out; I say that with authority).
- TheOnly92 14y agoIt's nice if go run doesn't check for these errors while go build does.
- FigmentEngine 14y agoits open source https://code.google.com/p/go/source/checkout https://code.google.com/p/go/source/checkout go change it? and a flag or similar on go build and put it to the community?
- iso-8859-1 14y agoIt wouldn't be accepted. It's not an error by accident.
- nnq 14y ago> if something is worth warning about it's worth making it an error Why oh why do people think this way, totally conflating things?! It makes any "explorative programming" extremely painful. Really, can't I indulge in a sloppy coding style while prototyping something, have a zillion warnings pop up (or silence them with a compiler flag), have a working prototype with ugly hacks and worst practices and then move on to slowly fix the things till I get a 0 warning 0 errors "clean state". Not all have the god-programmer mind to start with a "good design". We grow things organically, function by function, class by class. We start from a "ball of mud" and slowly mold it into the shape of our desire (now I agree that for the different style of programming that starts from a "good design" and works hard to prevent everything from turning into a ball of mud, having straight jackets" is good, but if I don't want to live in your "cathedral asylum", then don't force me to wear one!). Every line of code is and will be rewritten time and time again. And you need warnings and errors to be very different concepts to do this style of programming!
- rogpeppe1 14y ago> Really, can't I indulge in a sloppy coding style while prototyping something I sympathise with this view, but personally, as a full-time Go programmer, when I've been hacking up little piece of throw-away or explorative code, I've generally found that not-used errors have as often been helpful as annoying. For example, the compiler might say "i not used", and I'll think "bloody compiler, let's delete the declaration", but I'll actually find that I've named a loop variable wrongly and that this would have been a hard-to-find error requiring a few edit-run iterations, and thus I've actually saved more time by doing what the compiler asked than if I'd been able to code sloppily. If I do find myself adding and removing many print statements from within a package, I'll sometimes add a little function: func logf(f string, a ...interface{}) { log.Printf(f, a...) } then as long as that function exists, I can add a logf call to any file in the package with no need to add and remove imports. We can still start with mud, but it's good mud. BTW we have warnings too, but they're generated by a different tool, go vet, which printf format checking and the like.
- NateDad 14y agoThis. I can't tell you how often I've found that I accidentally shadowed a variable when I meant to use it, and this saves me from banging my head against the table to find the error.
- jacques_chester 14y ago> I'm all for opinionated language design, but when you use your compiler to cudgel your coders at the cost of productivity, you lose. Well, the thing is that in the long run, the cost of any software system is dominated by fixing bugs with high degree of latency. Removing various classes of error by compiler fiat is an approach that is wildly unpopular but well studied. This sentence might have been written as: > I'm all for opinionated language design, so long as I agree with the opinion. And that's fine. I can only speak for myself when I say that while younger me was annoyed that the damn compiler won't get out of the way, older me is annoyed that the damn compiler didn't catch this obvious defect for me. The difference is that older me is writing less trivial programs and dealing with more existing code and writing more complicated systems.
- anon1385 14y agoIt seems to me that the kind of people that are keen to have their compiler eliminate classes of errors in this way most likely won't be attracted to Go because of its other 'deficiencies', like null/lack of option types, lack of generics, mutability and so on. So it hits an uncomfortable middle point: 'annoying' to use, but still doesn't provide much guarantee about classes of error that most people would consider more serious than importing a module you don't use. (The latter is much easier to implement though, and that seems to have been a big driving force in various decisions about the language) Disclaimer: I've never written a line of Go, so this is just my perception as an outsider. Go does seem to get a lot of flack from people with theoretical interest in programming languages (think LtU commenters). My speculation is that this is partly pushback against the (perceived) 'Go was created by the smartest guys in the industry' memes, along with the fact that it ignores most of the last 30 years of PL research.
- jacques_chester 14y agoYes, I remember there was a great deal of wailing and gnashing of teeth when Go first turned up. My personal favourite was the bloke who compared Go to "Brand X" and found that the latter (which is older than C) was the better language, in his opinion [1]. I mean it's not as though using type system technology invented in the 1980s would have been such a stretch for a language created twenty-something years later. The thing is, though, that Go has gotten lots of para-language stuff right. It ships with gofmt and inbuilt tools for manipulating code, it has decent concurrency out of the box, it compiles and runs fairly quickly. It's really meant to be a better C from a universe where C++ was never invented (I've seen it compared to Limbo, a language developed on Plan9 -- given the heritage, that would make sense). [1] http://cowlark.com/2009-11-15-go/ http://cowlark.com/2009-11-15-go/
- kybernetyk 14y agoLike most opinions about programming languages mine is highly subjective. So viewer discretion is advised: What OP describes is exactly what drove me away from using Go for my 'high level' projects. Now Go is a great language with great ideas but hacking something together in it is such a pain that I don't get a warm feeling when thinking about coding in Go. All those small things add up to where it just gets tiresome. Not something I want experience during programming. There should be some kind of "I know what I'm doing"-mode that lets you import unused packages, etc.
- felixge 14y ago> Now Go is a great language with great ideas but hacking something together in it is such a pain that I don't get a warm feeling when thinking about coding in Go. All those small things add up to where it just gets tiresome. Not something I want experience during programming. This has exactly the opposite effect on me. I feel the strong grip of the compiler greatly comforting me during development. Form frees.
- amirreza 14y agoyes, Go is a very radical language with very bold decisions in its design and it sure has the "Just Say No" attitude.... but to be honest, its one of the main reasons for me to love Go!! because this makes me sure that Go will not end up like C++ or other bloated languages! you turn your head around, and there is a new feature in language. that sucks.
- p0nce 14y agoI don't see the problem with features. Actually none of C++'s new features "suck".
- ableal 14y ago(Footnote 1:) "Why don't we have a word for this? By "unit of hacking", I mean the work that goes on between starting to hack on a change-set and doing a commit." Hackit. As a unit, Ht, similar to Hz for Hertz. (I was going to add it would be named for Jim H. in http://en.wikipedia.org/wiki/Yes_Minister http://en.wikipedia.org/wiki/Yes_Minister , but his name was Hacker.)
- someone13 14y agoOne thing I always thought would be interesting to do is make it such that the "enforced stylistic" bits of a language were tied to the optimization settings. For example, make warnings not halt the compile on the compiler's equivalent for -O0, and then on any higher optimization setting, they become compiler errors that can't be turned off. It doesn't completely prevent people from doing stupid things (e.g. deploying a debug binary to production), but it's, in my opinion, a good way of solving exactly the problem mentioned here.
- meaty 14y agoThe objection here is that "I can't hack and hack to get the answer without inconveniencing myself". I watch people using this approach all day every day and have to sort out the shit-tip mess that is left behind because it ends up with sprawling crap. Stop. Think. Write it once. Test it. Fix it. Done. The "think" bit is the most important bit but is lost now that instant feedback is possible in favour of keep changing it until it looks like it works.
- realrocker 14y agoIt's noob babies all the way down to the turtles. Use a debug function!
- xycodex 14y agowow if this is the #1 criticism of the language, it must be really good
- DanWaterworth 14y agoI can't remember its name, but there's an effect whereby syntax and style are discussed more than semantics because they are easier to talk about. This is far from the worst thing about Go.
- jacques_chester 14y agoBike Shedding.
- DanWaterworth 14y agoI'm thinking of an effect that is specific to programming languages.
- stcredzero 14y agoThat's a good one. I've also recalled that a field being dominated by arguments over things that are not correct or incorrect but merely matters of personal opinion and taste is a sign of a "dead field." Repeated recurrences of the same idea repackaged as the "new" thing is another sign of such. The takeaway: One's time is better spent writing useful code.
- swdunlop 14y agoThe OP offers up Python as an example of "weightlessness", which I take as meaning "it will execute any code it can parse." Languages with this kind of tolerance require exhausting levels of diligence to verify assumptions and ensure consistency in a development team. Go's pedantic compiler and style enforcement fade pretty quickly into the background with practice and a reasonable text editor. The pain of trying to fix mixed metaphors between modules in Python never will. As an aside, here is the solution to your fmt.Println problem: func traceln(v ... interface{}) { fmt.Println(v...) } Just bind the function, and you can comment or uncomment traceln to your heart's desire.
- stcredzero 14y agoWhat (and in what context) do you mean by "binding the function?"
- dalke 14y ago"Languages with this kind of tolerance require exhausting levels of diligence" I don't understand this statement. People successfully write large Python programs and don't get exhausted in the process. Could you elaborate on how "mixed metaphors" affects things in Python, and how Go's syntax checks eliminate that problem in Go?
- deleted 14y ago[deleted]
- tehwalrus 14y agoWhile this is incredibly annoying (when trying to write some toy programs in go when it first came out, the 'unused variable' thing hit me so hard until I found out about using _...) I think the 'editor plugins fix this' response is probably the best - but please comment somewhere with a list of editors/plugins that have such intelligent go support so we don't have to roll our own!
- tshadwell 14y agoAs someone who has moved to using Go whenever it is possible and reasonably appropriate, I don't find this a particularly large problem. Yes, it's one I encounter, but only once the package is finished and I am in the testing stage and need to debug. Then, the fmt import stays there until I'm done fixing bugs, and I just use gocode's `:Drop fmt` to drop the import. Syntastic, which is a brilliant code validator for vim uses the go compiler to point out every place I have placed an fmt.Println with >>>, allowing me to remove all of them in one fell swoop, where in other languages I would have to search through the code for various print statements. The vanilla Go compiler also points this out, as the author notes. I prefer the way the compiler works because it makes sure your code is always representative of what needs to, and happens. To the author I would say "Why comment out the fmt.Println if you are still debugging?" and "If you are debugging, why only one fmt.Println?".
- jalfresi 14y agohttp://golang.org/doc/faq#unused_variables_and_imports http://golang.org/doc/faq#unused_variables_and_imports The reasons and choices made for this have been fully explained.
- rwj 14y agoI've found Go to be brilliant in some areas, but very irritating in others. I've lost the link to the talk where Rob Pike describes the reasoning behind the language, but once you understand that they are optimizing for large code bases in large organizations, a lot of these irritating decisions make more sense. In this case, the OP is running up against a trade-off in short-term convenience against long term code hygiene.
- jerf 14y agoYesterday I was complaining a bit about Go, so let me partially balance the scales by observing that in terms of examining this for use at my work, I absolutely love this and consider it a major plus point. Dealing with "fmt" is annoying, yes, and I sort of wish I could exclude that module from the rules. But I currently live with a huge code base in Perl, which is as far away from Go on this matter as it is possible to get, and after years of cruft buildup, it's virtually impossible to ever remove any imports from a module. You just can't tell what will happen, ever. Removing a "use X" from module Y may in fact break very-distant module Z because it happened to directly invoke X::function without ever having loaded X itself, it was accidentally depending on X being loaded by Y. Yeah, that one's easy enough to find and diagnose, but these get arbitrarily subtle.
- rartichoke 14y agoThe solution is to use gdb instead of printing variables in your code for debugging purposes. Go has great gdb support and gdb is a great debugger. There are also multiple editors that support gdb plugins if you don't want to deal with it in its raw form which honestly isn't that bad once you're used to it. I think I could say with a straight face that you will be able to debug a program faster with gdb than sprinkling about print statements even if you didn't have to worry about unused variables. In other words, get used to what the language has to offer and then leverage it before saying it's annoying. The problem you have is 100% solved by gdb.
- voidlogic 14y agoI write Go every day, I was going to rant about the author being annoyed minor things (that do not annoy me conveniently), and then it struck me- I'm extremely annoyed by the author wasting a line every time he repeats his code rather than doing this (or something similar depending on case): if _, err := ioutil.ReadFile(path); err != nil { return nil, err } Then I realized, programmers as detailed people are easily annoyed, because small details often matter. But in both the case of the author, and myself here, we need to realize when it truly doesn't matter. Sure these Go behaviours might annoy him, but they are important for large code bases and are easily worked around. Sure, repeating am overly verbose block several times annoys me, but the seven extra lines of code does not make him unreadable or incorrect- Here is too not sweating the small stuff.
- stcredzero 14y ago> Here is too not sweating the small stuff. 3 letters of irony here.
- voidlogic 14y ago:)
- FigmentEngine 14y agosee http://golang.org/doc/faq#unused_variables_and_imports http://golang.org/doc/faq#unused_variables_and_imports
- nvcnvn 14y agoAll the inconvenience will be solved if someone built a great IDE. (great like Netbeans for Java or VS for .NET :D, but with someong Gedit or Notepad is great too!) I think we have a vim puglin function to automatically import/remove.