New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: spec: make unused variables not an error #43729
Comments
I'd like some references, if possible. It can be annoying sometimes, sure, but I quite like this error, actually.
This is not the way to get rid of it. The way to get rid of it is to get rid of the variable that you're not using anyways. If you're just debugging and need something removed temporarily, just comment the variable out. If you're not using it anyways, it should generally be pretty easy to do so. The only time I've found it annoying is when it's a variable declared in a condition or it's part of a multi-return value declaration, but it's still only a minor annoyance. Personally, I think that the benefit, namely making sure that you don't have pointless local variables laying around, cluttering up your code, outweighs those annoyances. |
Only somewhat. Rather than just complaining about the error, I'm pointing out that by the very reasoning in #1085 it shouldn't exist. Many people find this a matter that shouldn't be fixed. Therefore, Go shouldn't complain about it. |
It will be very time consuming to go on the web and look for every individual finding this annoying. Someone on a Reddit post even thought it was a joke and actually looked up Go to see if this is an actual error. Regardless, since there were three other issues mentioned as potential duplicates and an FAQ section dedicated to this, I will say this is enough to show this this is more than a couple of people who find this a bad part of the langauge.
And I dislike the error, so we're equal. :P Jokes aside, I opened this issue in the hopes that Go moved on from the days of "GOPATH is best and we'll ignore all the negative feedback even if only 10 people will actually like our way". I mean no offense if you're one of the people who finds this useful, but is this good enough when it annoys or even hinders many others?
But what if I'm using it, just not in the way Go expects me to? For example, a common thing I do in other langauges is to declare a variable for the result of a function and then debug until there to see what the function will return. The use of that variable is just to see its value in the debugger, yet Go can't know that it's useful to me. Or maybe its use is planning ahead, making an idea of what the code will look like. Even if I don't use that variable yet, maybe it will help me to have it there, with the function that creates it called already with the right parameters, but the part that uses it not done yet. If I'm gonna uncomment it later, why comment?
The benefit is a couple less bytes of code. At most a slight visual disturbance in a little piece of the code. The downside ranges depending on people from mild annoyance to workflow disruption, especially people used to other langauges. To me, the benefit is insignificant and the downside is quite big. And, finally, once again, if it benefits you, that's great! Just like the FAQ proposed a tool as a potential (but imo bad) solution for the unused import error, I propose a tool - a linter - that can be used to give you this error back if it is removed from the compiler. All I'm proposing is that this benefit for some should be kept, but the hinderance to others should be removed. |
You say this is a big downside for a lot of people, but I can't see any evidence for that statement. For example, if it truly were one of Go's biggest problems, or one that most newcomers struggled with, I would imagine it would show up in developer surveys like https://blog.golang.org/survey2019-results. Personally, I do see some newcomers surprised by the Go compiler's stance on errors and warnings, but everyone I've worked with gets used to it after a few weeks. There are clear benefits to having this be a compiler error, because it means the check is widespread and hard to ignore. The only downside I see is getting used to it, or the slight annoyance while running unfinished code. But again, I don't see any proof that this is actually a large problem for a lot of Go users. |
This error has save me many times in cases where I thought I was using a variable, but wasn't. It should stay as it is very useful for this case. |
@beoran As I said, this will be equally as useful as a linter, who would also be able to point it out to you. It just wouldn't bother those who find this one of the pain points of using Go anymore. |
@mvdan Those developer surveys are not entirely representative of everybody. In particular, they're not representative of people who wanted to learn Go, got screamed at by the compiler and were confused until they found out that you can't have else on a new line and, out of frustration, gave up on learning Go. (Speaking from experience from the first time I tried Go, back when Go modules didn't exist). At that beginner level, the advantages of Go might not be too clear, and, when faced with an overly restrictive compiler, C++/Python/Node.js do just fine, why bother fighting with a mean compiler and a confusing language? And since those people generally don't stick around in the Go community to express their disappointment, they're not really heard. They just silently come and go. Since I didn't hear of that survey until you linked it, it's safe to say that only a certain category of people are represented by it. I'm not saying that this only affects beginners (on that Reddit post I linked there are a couple of Go users who point out that this is one of the annoyances of using the language). All I'm saying is that quoting such a survey where in all likelihood there's mainly people who like most or all of Go answering isn't exactly the perfect counter argument. "100% of people who like it say they like it"-ish. |
A linter people have to enable will be used by fewer people.
I'm happy to hear about any other way to objectively measure the impact of this compiler error. Personal experience is not really representative. Similarly, online threads tend to attract vocal or unhappy people, so they aren't a good way to get an overall picture. |
respectfully this is a mutated version of the “no true Scotsman” argument. Four yearly surveys have not shown that unused variables are a significant cause of complaint. Ignoring this inconvenient fact does not validate your arguments. I understand that this decision, which was made in the earliest days of go’s development, is not your personal preference, but please understand that of all the things which are unlikely to change in go, this is at the top of the list. |
That's the point? Since not everybody appreciates or wants the error, the logical conclusion is that there will be fewer people.
"Does it need an FAQ entry addressing the issue?" would be one. Since enough people complained that it warranted a detailed FAQ entry, and complaints come in even after that, would that not be a good enough measure?
So only people happy with the situation should be listened to? Back to "100% of people who like it said they like it"?
Not only listening to them, no, of course. But does saying "those opinions aren't valid" not reduce the quality of the overall picture?
Wasn't "write all code in GOPATH" the same?
Back when Go modules weren't a thing yet, I was figuratively screamed at when I complained about GOPATH being inconvenient. It was the best way to go and it was never gonna change. Now it's soon entirely gone. Recall that this was my reasoning for bringing this issue up in the first place. Langauges change as they evolve. Maybe if this decision was made early in development, it might mean that it was made without having the community of today to consult with and it might have been a bad decision? Of course, it's totally a possibility that only like 1% of Go users dislike this. Maybe for people who got used to it it's just annoying on the spot but it's not annoying enough to remember to write it in the survey. I may be a minority and in that case fine, not everybody must fully enjoy the language. At the same time, quoting just the survey and ignoring what people of online forums say feels a bit like sticking the head in the sand. Which can be acceptable. After all, the core team decides what the language should be. People who like it will use it, people who don't will use something else. C'est la vie. There will appear an issue about it every once in a while, respond with link to FAQ, marked as duplicate, closed, bye. I just wanted to try to make a case. |
Oh, also, about that survey and related to "other way to objectively measure the impact of this compiler error". I see it's a survey of Go users. Maybe a survey of people who tried Go but abandoned it would also be helpful? "What made you leave?" |
UseLet me quote purplepharoh from that Reddit thread: "The thing about GO is that it enforces good practices with compiler errors. For example this could be a warning but most people ignore warnings and often don't fix them, good practice is to remove (or use) unused variables so GO enforces this." This is an essential feature of Go which ensures consistency and minimum code quality. Code is read more often than it is written and unused variables left over from development are a hindrance to reading. An unused variable definitely is bad practice since it indicates unfinished code or messy code, or worse, a shadowed variable. The latter often happens with err error variables. For your use case of return values in the debugger, just declare your function with variables for the return, e. g. func Square(in int) (res int). For planning code, your functions are too complex if you want to add unused variables in there for planning purposes. Besides, in other languages, they have the tendency to stick around when they end up being unneeded after all, or become redundant. I had similar feelings about Go 10 years ago when I learned Go, but I changed my mind after a few months. While the Go approach of enforcing good practice takes some getting used to, especially when coming from a different language, once you get the hang of it, you'll reap the benefits. |
It's also worth noting that Go is opinionated by design. If a developer wishing to learn Go has strong convictions and is not willing to keep an open mind, it's likely they would not like Go at all. There are dozens of ways in which Go differs from other mainstream languages, and this is just one amongst many. |
My problem isn't with wanting to ensure readable code. Rather, my problem is with writing code being impeded. What good is making written code look nice if the code won't be written in the first place. The ideal solution would be to be able to debug the code ignoring non-essential errors like "you didn't use the variable". But since the Go team says that compiling flags for this shouldn't exist and this is all or nothing, I came here to argue for "fine, nothing then". @beoran That doesn't really fix my usecase since it's not always my function. In particular, functions aren't always pure, and they have side effects. Perhaps I want to debug such a code: socket, error := connect(address) Here, Go would complain that As for planning, writing that line above yet not doing something with the socket yet doesn't sound too complicated. @mvdan: Understandable, just as Go was opinionated some years ago about GOPATH being the one and only way to go. So then why is GOPATH deprecated? As I said previously, I don't necessarily mind Go being opinionated, I just think that maybe the current opinion is not the greatest one? |
Some people will say that the way Go does X is the one true way and it will never change, but that's not really the project's stance. If something has good arguments to be changed, enough to outweigh the disadvantages and the breaking/confusion of existing users, it can happen. Modules brought great things, like reproducible builds and dependency management. This change, as far as I can tell, just avoids a minor annoyance that few(?) people actually struggle with. With that said, I feel like I'm repeating myself and I don't have anything else to add here, so I'll stop responding for now :) |
Just as a historical note, the handling of unused variables does date back to the earliest days of the language. |
This is one of my pain points as well with Go. It doesn't do anything often, and when it does it's frustrating. The unused imports was another equally frustrating, it's good tools do it for you nowadays. Maybe we need a tool that transparently adds |
Unused imports are indeed also annoying to me, but from a different reason, and tools don't help with that. The reason is autocomplete. Don't add import, autocomplete doesn't know of what function you want to call. Add import, autocomplete complains that the import is not used yet. But autocomplete is merely an extra convenience, reading the documentation of how to call a certain function before autocomplete will help with the rest isn't too bad. That's why I only complain about unused variables, which is an error that's actually annoying and at times quite workflow interrupting. And to give not much back as a benefit. I'm not saying I'm an expert top 3 programmers of all time, but I can't recall any time in using another langauge where not using a variable created any problem.
In particular, these are some examples, and only the last one is remotely useful (maybe restrict the error only to shadowed variables?). For the other ones, perhaps that shows my ineptitude, but I don't write finished code in one go. I write some unfinished code, run it, see how it behaves and go from there. Not being allowed to run it because it's unfinished is quite a hinderance. |
@dancojocaru2000 writes:
I am not sure how useful a "printed representation" of a Go socket structure would be, but purely hypothetically, you could add something like:
You now have a usage, and you can also see them in the debugger, should you choose to run them under a debugger. You could also write a small variadic shim around that (possibly called |
tbh: this error prevents me from using Go. |
This is so true ... |
Code with unused declared vars is considered as bad practice. |
To be quite honest, if my goal was to do rapid prototyping I would probably not be using Go as the tool for that. Maybe we should align on whether the desire to use Go in that way is reasonable / aligned with the language itself. I am not so sure. Can you do it? Sorta, but it depends on what you're doing. I love Go and it's definitely my tool of choice, but I am not sure it's the tool I'd use if I was engineer number 1 at a startup looking to launch my product when I know rapid development / iteration will be important. It feels like a much better fit when you're more confident in the architecture / shape of the software you are building. Realtalk, even if you make this change it's not going to be anywhere near as rapid as other languages, and I think some of that is intentional relative to the language's overall design choices. Should we be using that as an argument for change? I never got the feeling that rapid prototyping / development is an explicit goal of Go. Heck, one of the Proverbs is "Clear is better than clever", and in my experience clever things tend to be helpful when you're trying to rapidly prototype but not necessarily build software that has a primary goal of the code being easily maintainable. I'd rather continue to lean into system safety, and don't personally feel the trade-off here is worth it (considering the arguments presented in favor of the change). That said, if there is a compelling safety reason to consider that I would love to learn about it. |
Why doesn't Go make an option for the compiler to simply give a warning instead of an error? I feel like providing this option would make it more convincing for developers of other languages to use Go as well... |
@Nathan13888 they address that question in the language FAQ on the topic this issue is raised on: https://golang.org/doc/faq#unused_variables_and_imports
|
I could see where they are coming from and why some people would want warnings instead. Personally I don't mind but don't agree with giving errors for such a small thing. Also, I don't understand why a language wants to restrict it's users in such a way. A language should provide all the tools a developer wants to see. I don't see a problem for a language to be opinionated but being restrictive is not cool. |
@beoran that's part of The Zen of Python, not Go |
@theckman Whoops, you're right. although https://talks.golang.org/2012/splash.article and other articles about Go mention the word "explicit" a lot, they don't refer to this Zen of Python in particular. It is still an important concept in Go, though. @samlof I do use the debugger, when I don't know what my code is doing. Which is bad, and means I have to rewrite the part I am debugging, if possible, so I do understand what it is doing. The sooner a bug is found the better, and if the compiler can find bugs for me, I'm all for it, even if it costs me some convenience. I don't consider Go the perfect language. It is hard to use well for really low level programming (graphics, OS, C interfacing), due to the garbage collector and segmented stack, but those are semantic problems, not syntax or error checking problems. It's true in general that Go is semantically different in several ways to Rust, Kotlin or Swift, even though all four are brace block languages. I agreed, as I said before, that in the beginning, these differences are annoying. But the best way learn Go is to leave your other languages at the doorstep, and accept those differences in stead of struggling against them. Then everything falls into place that much sooner. |
Personally, I tend towards "extensive debug logging", which naturally causes any variable I want to see what happens to being used (because it'll be referenced from the debug logging statement). It is also frequently the case (for me) that my workstation is not a suitable environment for the binary to run (the code I write tends to run in kubernetes clusters and frequently needs to work with different RBAC restrictions than my account has), so attaching a debugger to the running binary is actually seldom an option for me. I think I last intentionally attached a debugger to code I've written well over a decade ago. |
I think it's completely fair for Golang to have a different philosophy and to do its own thing. Go is different from other languages in many ways, and there's value in that. But I also completely empathize with people who are annoyed by unused variable warnings. Personally, this error really breaks my flow, but I understand that there's a different point of view, that Go is opinionated and forces people to fix things, and it's a reasonable one. The code in the compiler responsible for this behavior actually doesn't change very often, if it bothers you it's totally possible to apply a small diff and rebase it when a new version comes out. I don't recommend you go and blindly apply this locally, but to put my Now, a disclaimer: The patch above is a quick, dirty hack and not intended for wide/serious/production use, and especially not intended to be merged upstream! If your laptop catches fire as a result of running this patch, or if your code is miscompiled, I will merily deny all responsibility! When I say that it's a PoC, I mean it! Don't expect the test suite to pass =) Go has its own philosophy, maybe you have yours too. And maybe that's okay 🙂 |
This is a fundamental day-one decision, along with unused imports being an error. |
Weren't GOPATH or the lack of generics also fundamental day-one decisions? This, alone, is not a good argument to justify keeping something.
Software engineering reasons there sure are, but if they were that good then people wouldn't have complained. To reiterate, I don't find those reasons good enough to justify preventing an otherwise functioning program from compiling, and going by the "And if it's not worth fixing, it's not worth mentioning." philosophy, the error should therefore be removed.
Since this implies that you've seen those reasons brought up to me, I would assume you've also seen me finding them not worth the tradeoff. This is therefore just reiterating something I disagree with. |
No, they weren't. |
Glad to hear. Some years ago, suggesting that either of those things were bad on forums and the like was met with huge disapproval, which did give the feeling that the language developers themselves had a grudge on generics. |
Even in the Go 1 release in 2012 the FAQ said "Generics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do." |
This proposal has been added to the active column of the proposals project |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
As somebody who used a lot of other languages, and is playing around with Go (to read repositories that I do not write or maintain, e.g., Docker, etc.), the language has some nice things going for it. I am honestly looking for a decent cross platform alternative to C/C++. The setup process for C/C++ is hard on Windows (get Visual Studio or MinGW), and the languages definitely have flaws (UB, etc.). However I'm already kinda annoyed, sorry to say. I don't know if I'm going to enjoy using this language, if I don't, I'll use it as little as possible (just to hack on repos/etc.). It's my job to make the code readable, I feel like the compiler's just taking tools away from me (tools that some people misuse, I admit). I use local variables for debugging / "pay attention to this variable", some of which are maybe unused, the same reason why I might leave a debugging trace on a board and tell people to measure it. It signposts better than comments because they are validated by the compiler and can't go out of date as easily. I resent that the response is "just comment it out" which is unambiguously a worse practice than an unused variable. Every language has its ups and downs. Maybe Go will have some nice features to make up for this. |
Use |
I'm aware of the workaround, I read most of the posts on this issue. To me it's a language quirk to remember, maybe other nice things about go will balance that out. |
I don't see how purposefully leaving unused variables in the code improves readability. Are they not essentially red herrings?
I vehemently disagree with this. |
This error has saved me many times where an inner variable shadowed an outer one accidentally. Once this happens , one starts to appreciate how useful this feature of Go is. |
Many people opposed to this error will not show up in developer surveys. I stumbled across this issue and am one of those that will never use Go (or Zig) because of how badly this error interferes with my iterative development process. I'll go back to 'not existing' now. |
This ship sailed a long time ago. Locking. Edit: see also https://go.dev/doc/faq#unused_variables_and_imports. |
Seeing as Go is a tiny bit more open minded, going from "GOPATH is the best and only way and it will always be this way absolutely totally" to soon removing it entirely, I'm taking my chances.
A lot of people find no value in this error. Furthermore, many people find it as a hinderance, a bad part of the compiler and the language.
And since the way to get rid of it is simply to
_ = variable
, which changes nothing in the behavior of the compiled program, this error helps solve nothing related to the running of the program. It's just an annoying reminder of "you forgot to explicitly ignore the variable before you debug and then make actual use of it later anyway like it always happens".Therefore, according to the FAQ's reasoning: "And if it's not worth fixing, it's not worth mentioning.", Go should stop mentioning this.
And just in case, to address the potential question of "But what about people who find this useful?".
Other languages deal with this easily using linters. That way, people who find an use in this error can keep it, while not impeding both the productivity and joy of many others.
The text was updated successfully, but these errors were encountered: