-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
compile errors for unused things #335
Comments
Would you be able to easily disable these errors? They could get annoying when you're debugging something by e.g. commenting out sections of code. (How does Golang deal with this?) |
You could disable an error by doing |
On a related note, the "unreachable code" error is already annoying sometimes, albeit far less annoying than "unused import" errors would be. Adding a "return" statement halfway up a function for testing purposes is something I (try to) do often. I really wish there was an option to turn these into warnings (as an opt-in compiler flag). Some Go developers say[1] they "get used to" the errors after a while, but there must be a better way (not involving an IDE plugin)? Adding underscores really slows me down when I'm trying to troubleshoot something, constantly commenting/uncommenting and recompiling, and I have to scroll to the top of the file and add/remove underscores from imports every time as well. I'm not always the most patient when trying to learn a new language at home and troubleshooting problems. And then it certainly doesn't help my mood when I search for the problem online and get official FAQs[2] lecturing me not to leave code quality for later and so on. [1] https://groups.google.com/forum/#!topic/golang-nuts/OBsCksYHPG4 |
But here comes the tricky part (as if it's not tricky enough already)! Hot code swapping #68. If implemented, hot code swapping will the favorite feature among those that want to make quick experimental changes and see the results immediately. For example:
The function crazyStuff has been created to contain all of the code additions that you want to experimentally turn on and off while the game is running. If every time you commented out crazyStuff you had to comment out not only crazyStuff itself but all of the functions that only it calls then the speed advantaged and comfort of hot reload is substantially reduced. With hot code swapping do we even know which functions might get called? Edit: Would a comptime { _ = crazyStuff; } block solve this? Is it that simple? |
In my opinion the main problem is that this is caught earlier than real compile errors, and that is what hinders (at least my) development workflow. Unused variables, and any of the other errors proposed in this issue / errors which do not affect the ambiguity of the source code, should not stop the compiler from moving on to the semantic analysis phase and generating additional errors. That would at least partially reduce the issue. IMO thats a prerequisite before implementing any of the other errors. |
The fork exists. It's called "unzig". Repo here: https://github.com/markisus/unzig I'm sure he would welcome patches for 0.11 as bootstrapping it from 0.10 is kind of a PITA. |
This is years old but still ongoing and still being stubbornly opposed for some reason, so I'll leave my two cents anyways: I've followed this language since when using loops with incorrect syntax would segfault the compiler, several years ago at least. Documentation, an unstable api, and no package manager has always been an issue, but the singular absolutely massive reason I can't get into using this language even though I'd absolutely love to, is decisions like this made for no objective gain and to the detriment of many users just to suit a small number of people's whims. No, 'suit' isn't accurate, I meant to say ENFORCE, preferring one way would be fine as long as people could opt-out. Things like not having multiline comments to comment out blocks of code and expecting people to either comment every individual line out with a single line comment or to use a 3rd party tool Or not being able to use tabs in code for a very long time, although this seems to have changed since I last checked And now severely slowing down rapid inline testing and debugging of code by causing compile errors, not warnings, for something as common as a temporarily-unused variable, and future plans to go even further judging by the task list. I have never, ever in any language had a bug resulting from an unused variable, and even if I had, a warning would be enough to solve it. These are things no other language I can think of does/did without at least a way to toggle them, and for good reason. I want to love this language, and there's a whole lot to love, Zig was the betterC alternative that I'd been looking for since years ago, but some things are just a dealbreaker for a language I'd be using because I want to, not because I need to. |
The strict behavior of not allowing unused variables does have its merits, but there's been enough comments here explaining why an escape hatch is required (debugging, experimentation). I suggest that the escape hatch takes the form of a builtin
This would hopefully give the best of both worlds. Don't get in the way of experimentation, but also enforce higher quality in code that is meant for reuse. |
If a built-in approach is decided on, I would personally prefer it to be:
I'm unsure about this approach. One of my current projects is a networked multiplayer game, and I have the My industry experience is predominantly in C++ gamedev (my company is also particularly fast paced). In my time I have seen unused variables be the cause for several bugs, and so I am definitely for unused variables being an error (and I'm working our C++ codebases towards this). But experimention, prototyping & debugging is incredibly valuable to us, and temporarily unused variables are part of that. |
I disagree. I solely use For purposefully unused variables (eg. function arguments that are only there in order to fulfill some interface), I instead simply name them EDIT: silly me, I forgot about discarding function return values. A regex like |
So by your own admission, your suggested alternative can fail with edge cases. Please don't misunderstand, I'm not trying to be snarky; most people would have silently edited the message and not admitted to the error. I very much appreciate your honesty. But this is a fact: Trying to use outside methods is a trail and error problem, and could lead to missed unused variables, hidden away by an underscore. |
No, I simply forgot a valid usecase for |
This is a manual step though. It means the compiler is not even catching the issue it is meant to catch (unused code). You have to manually run a regex over the codebase to delete these. What if another developer doesn't do this? Do you have to add the step of finding all This single "feature" is the reason I dropped Go shortly after learning about it (its basically a complete deal breaker). It is a shame that some new projects are baking in very opinionated features at a level that is not overridable. My understanding was the aim of Zig is to replace C, this doesn't really help that aim. |
Yes. I was specifically responding to @Katipo007's claim that these cases aren't easily searchable. The error still helps find unintentional discards, and a linter or similar can find intentional temporary discards, like the ones my regex detects. Yes, it's an extra step to run a linter, but if you remove the error it's also an extra step, and most people run linters as part of their CI already, in pretty much every other language. |
Some compilers also perform linting functionality along with their error checking, and call the reports for these lints "warnings". Zig could offer these lints, without requiring an external linter. |
Hard agree with both, sometimes code iteration is more important than compiler speed, this is already partially a status quo position with things like instances of structs being able to call static methods, implicit passing of self, implicit types, etc. Here's my idea for a solution:
This should obviously not be the default option, but would still give developers the possibility to not get hassled by the compiler at literally every step of the way. |
I am new to Zig, coming from Rust. There you may name a var _name to show, this var is allowed to be unused. |
Should we also add a compile error for "unused mutability"? const Foo = struct {
x: u8 = 0,
// IMO this should compile error, foo.x is not assigned
pub fn unnecessaryPointer(foo: *Foo) u8 {
return foo.x;
}
pub fn necessaryPointer(foo: *Foo) void {
foo.x = 42;
}
};
test {
const const_foo = Foo{};
// currently compile errors here
_ = const_foo.unnecessaryPointer();
// this correctly compile errors
const_foo.necessaryPointer();
var var_foo = Foo{};
// currently silent
_ = var_foo.unnecessaryPointer();
} If |
Pointer does not mean mutability. You can require a pointer for performance concern or to prevent copy of data that is not copy safe. |
Is that not a zig compiler's job to make the tradeoff to pass by reference or pass by copy for const? |
It is but it can get tricky in some cases so its not always applied. You can look at https://www.youtube.com/watch?v=dEIsJPpCZYg for more info. |
|
Should unused test {
const foo: u8 = 42;
const bar: *const u8 = &foo;
const baz = @as(*const u8, @ptrCast(bar));
_ = baz;
} |
@Pyrolistical, that's not "unused", it's just unnecessary. That is a separate concern. |
I thought this was worth a substantive reply, which will perhaps help other people who are dissatisfied with Zig's stringency in this matter. First point is that Zig is an excellent choice for the kind of code you're talking about, where there's a bunch of additional code which shouldn't be included in production builds. Zig has two features here: comptime evaluation, and lazy compilation, which mean that the errors for unused code have zero bearing on the ability to include this sort of code. You can define a condition in const options = b.addOptions();
if (b.option(bool, "diagnostics", "include diagnostic code") orelse false) {
options.addOption(bool, "diagnostics", true);
} else {
options.addOption(bool, "diagnostics", false);
} And then use it throughout the codebase, anywhere: const config = @import("config");
// later:
const answer = someStruct.askQuestion();
if (config.diagnostics {
someStruct.logABunchOfStuff();
} And you can use anonymous structs as namespaces, so this works: const toolkit = tools: {
if (config.diagnostics) {
break :tools struct {
usingnamespace @include("dianostics/report.zig");
usingnamespace @include("util/sha3.zig");
};
}
}; What's good about this is that This generalizes very nicely! For instance, you're writing a function, and you've only used Just do this const draft = config.draft;
// later
pub fn somethingWorkedOn(a:T, b:T, c:T, d:T) !void {
if (draft) {
_ = c;
_ = d;
}
// rest of function
} If anything stays unused, you'll eventually set Now you can rub out lines you aren't using, and you won't get unused variable complaints, it's just: if (!draft) thingYouWantNotToHappen(aVariableUsedOnlyHere);
Zig isn't Go: it has comptime and lazy compilation. If you work with the language, you can avoid the downsides of the compiler being strict about unused things, and still reap the benefits. I don't consider this a workaround for a deficit in the language, and you shouldn't either. Zig provides all the tools you need to make transient changes to your codebase without angering the compiler, and it makes it easy to keep the codebase entirely live, which is a considerable strength. |
Maybe, a macro that tells the compiler or zls not to report errors? Are macros possible in zig? C gives us #define. |
After spending half of my time debugging and prototyping fixing these errors, I have decided to stop using the language entirely. Hopefully Andrew reconsiders and allows us to convert these errors into warnings. Adding code to suppress these errors introduces new problems while only serving to solve a self-inflicted problem. Please reconsider. |
I am not interested in feedback on this issue. |
even unused pub functions are an error if they are not accessible from outside the packageNote that because of conditional compilation, some things may seem unused when they are in fact used but only depending on some compile variables. Some thought will have to be put into how to make this work without sacrificing compile speed or lazy evaluation.
The text was updated successfully, but these errors were encountered: