As an example, comptime could be used on expressions to enforce comptime calculation. But constant variables can also be implicitly comptime if their initialization is comptime-computable.
I think we could make a list on when an expression is implicitly comptime computed. In this way, we can know when there is no need to add a comptime keyword. AFAIK, you can add however many comptime as you wanted…
if (comptime comptime comptime hasTrait(...)) doSomething();
The difficulty we face (in my opinion) is the following question: what can we expect our compiler to know about our code without saying it explicitly?
The value of not having to specify everything is that there are certain optimizations that will be picked up even where we do not intend them (as is the case with compile-time known numbers). However, to be more explicit means that we can accidentally opt-out of many of those same optimizations by simply not saying them out loud.
When you say “The document” do you mean the official documentation? Or do you mean something more general like “the language should require us to be more specific overall”?
Is it correct to say that it’s guaranteed to do comptime evaluation if possible in the initialization of a constant? That is, the comptime keyword in the following code is guaranteed to be redundant?
const my_var = comptime compute(1, "hehe");
Any other similar cases? I think we can add a subsection/list in the document link above with such code examples.
Also, we need to make a distinction here between const and comptime. A good instance of this is in the typical declaration of strings [] const u8 which is a slice of constant unsigned 8-bit integers. The const there says nothing about comptime as it’s embedded in a non-const type.
the compiler gives you an error when your use of comptime is redundant. I don’t know if the first example (with multiple comptime keywords were used in a row) is a regression or if you’re using an older version of Zig, but ideally comptime should only be allowed by the compiler in locations where it does influence execution.
For example when initializing a constant in the global scope, you’re already in a comptime context and so all uses of it are redundant and will be reported as an error.
Conversely, initializing a const variable in a function body doesn’t mean that the value is necessarily available at comptime and so sometimes using comptime will have an impact.
I think it’s worth noting that even if you remove comptime, LLVM might still evaluate it at compile time as part of its optimization passes. You can check the generated assembly to see if it is actually just dropping the answer in the executable. This is something I encounter a lot when trying to use godbolt. If you have a function which doesn’t conform to the C ABI and therefore can’t export it, it’s difficult to get the generated assembly because if you have inputs known at compile time which are passed as arguments into your function it will often be completely optimized away. In order to see how it really compiles I have to read the function’s input in from an external file so the optimizer has no choice but to compile my code.