I would be fine with it if it only threw an error about that when building in release mode or if there was a flag to silence it temporarily.
But while trying out some things and learning the language I find it annoying. And I don't know how it makes me more disciplined when I can just write `_ = unused;` to suppress the error. Even worse, if I forget that assignment in the code the compiler will never warn me about it again even when I want it to.
Or the compiler could just add a flag and not make assumptions about my setup or workflow. Also linters are optional and under my control. Meanwhile the Zig compiler is forcing that onto me, and for what benefit exactly?
> I wrote a 16kloc Zig project a couple of months ago, and not once the 'unused variables are errors' thing was annoying
That's great, but different people are different. I've tried learning Zig twice by now but this is just a dealbreaker, simple as that.
The way I deal with this in my language, which also bans unused variables, is simple: I delete the unused variable or I use it.
My workflow is probably very different from yours I'm guessing. I have my editor configured to save on every keystroke and I have a watch process that then recompiles my code. I pretty much never manually compile. My compiler is sufficiently fast that I almost never wait more than 1 second to build and run my code. I notice every error immediately and fix them as they arise. This is what I am talking about with discipline. I never allow my code to get into an unexpectedly broken state and don't need a linter since I just make the compiler as strict as I would make the linter. This ultimately simplifies both the compiler and the build pipeline.
These are all huge upsides for me. The cost of occasionally deleting a definition and then restoring it are for me minor compared to the cost of, say, writing a separate linter or adding feature flags to the compiler (the latter of which doesn't fit into my workflow anyway since I auto compile).
The problem is that in order to delete an unused variable, you may need to delete a huge chunk of code which would be useful later when you want to actually use the variable.
can you give an example please? i can't imagine how any section of code would be affected by removing an unused variable. if the code reference the variable, it would be used. if it doesn't, then why would you have to delete it?
Wrong syntax is (and must be) an error. Totally different. The Problem in Go and Zig is that they put theory over practice: No compiler warnings is a good idea in theory, but fails in practice for things like unused variables or unused imports. Defending that makes it even worse and begs the question what other treasures they have burried in their language design. This thread is a testament to that.
You do. The zig compiler and stdlib can iterate faster across a team of mostly by numbers volunteer developers with varying degrees of skill and across global timezones because of the discipline that the compiler imposes.
This is nonsense argument, because there are more pragmatic solutions: Turn warnings into errors for release builds, or if there is only one build type, have a policy that requires developers to remove all warnings before committing code.
i am absolutely serious. pike for example does not need imports. if a reference is not found in the local namespace the compiler will find it in the module path and resolve it by itself. there is no ambiguity because each module has a unique name.
we accept type inference but don't do the same for module references? why?
pike does have an import statement, but its effect is to include all members of a module into the namespace instead of just resolving the ones that are really used.
and instead of speeding things up, using import on modules with lots of members may actually slow things down because the namespace is loaded up with lots of unused references. sometimes import is used to help readability, but that's rarely needed because you can solve the same with a simple assignment to a variable.
if you can show me an example where import resolves an ambiguity, i'll try to show how pike solves the problem without import.
I don't know how it works in Zig. In JavaScript, you can have lots of things with the same name, so you need to explicitly import them and you can give them an alias at the same time if there's a clash. I believe Python is the same.
In C++, you have to #include the thing you want to use somewhere, not necessarily in the same file you use it, it just has to end up in the same compilation unit. If two files define the same name, you'll end up with a compilation error. In very large projects, sometimes you won't notice this until some transitive dependency includes the other thing.
I'm personally a fan of explicit imports. I imagine this helps IDEs resolve references without having to scan 1000s of files to resolve them, and it helps build tools pull in only the needed files. Regarding speed (of execution), in JS we have tree-shaking so if you import a file but don't use all of its members, those excess/used members will be dropped from the final bundle (saving on both bundle size and run-time parsing). Plus it means I don't have to spend much time thinking of a super/globally unique name for every thing I define.
If you use fully qualified statements everywhere, sure. That means writing `datetime.datetime.now()` everywhere instead of `from datetime import datetime` and then just doing `datetime.now()`. But then you'll tell me, just create an alias, `dt = datetime.datetime`. Sure, I guess, but now you've made `datetime` some kind of superglobal so you can't use that as a variable anywhere.
And how does this work in practice? In Python and JS you can also put executable code inside your modules that gets executed the first time it's imported. Are you telling me that that's going to run the first time it's implicitly imported instead? Is that a good idea?
The story in JS gets even crazier because you can do all kinds of whacky things with imports, like hooking up "loaders" so you can import things that aren't even JavaScript (images, CSS, you name it), or you can modify the resolution algorithm.
but now you've made `datetime` some kind of superglobal so you can't use that as a variable anywhere
depends on the language, in pike, and as far as i know in python i still can use it as a variable if i want to, it would just cover the module and make the real datetime inaccessible. but why would i want to do that? if i see someone using a well known module name as a variable in python i would probably recommend changing it.
i don't see the benefit of not filling the global namespace over making import unneeded. add to that, by convention in pike module names start with an uppercase letter, and variables don't, so the overlap is going to be extremely small and never causes any issues.
In Python and JS you can also put executable code inside your modules that gets executed the first time it's imported
pike doesn't have that feature. if there is something to be initialized you'd have to call it explicitly. i don't see a problem with that, because in python you call import explicitly too. so you just swap out one need to be explicit for another. i prefer the pike way because it actually gives me more control over if and when that initialization happens.
i think that also better fits the paradigm of explicit is better than implicit. in python i have to learn which module does initialize stuff or ignore it, in pike i can easily see it from the way it is used.
further in pike to get an initialization i would normally create an instance of a class in the module because modules are singletons, and you probably don't want to change something in them globally.
going to run the first time it's implicitly imported instead
pike is compiled, that is, all these references are resolved first, before any code is run. so even if there were any implicit initialization it would be possible to run it first.
more specifically, pike modules are instantiated objects. i don't know the internals, but i believe they get first instantiated when they are resolved. again, that's before the rest of the code where the reference came from is running
I'm not sure I see the total difference between matching parens and matching defs and refs.
Sure, saying "an open paren must have a matching close" is quantitatively different from "a def must have at least one matching ref", but is it really qualitatively different?
Lets say I gather Diag data, which I conditionally print during testing. Are you saying that I cannot leave the diag code in place after I comment out the print function? Thats unproductive and a major obstacle to using Zig. I’m still pissed at Andrews stance of preventing Tabs, operator overloading, polymorphism, and this just seals my “stay away” stance. I really do want to like Zig, but cannot.
You don't need to comment out the print function - it could gate its behavior on a comptime-known configuration variable. This would allow you to keep your debug variables in place.
anything a linter can do, can be included in a compiler. or the linter can be part of the compilation process by default. iaw instead of being optional it should be required maybe with a special opt-out, but opt-out should be frowned upon.