On Wednesday, 28 December 2022 at 02:31:45 UTC, thebluepandabear wrote:
> In Java and some other languages, during compile time the code gets executed into Java bytecode. This also happens for C#. I don't know if there is an equivalent 'intermediate' language for D that your code gets translated to.
With statically compiled languages like D, C, and C++, the compiler ultimately translates your source code to what's referred to as "machine code". Compilers output object files, which are in turn linked into an executable file by a linker.
Static compilers can use intermediate representations like Java bytecode. For example, compilation could consist of two steps handled by two different programs, one that translates the source to bytecode, and one that translates the bytecode to an object file.
This is how LLVM-based compilers like Clang and LDC work. Clang translates C source to LLVM IR (Intermediate Representation). LDC translated C source to LLVM IR. Both pass the generated IR to the LLVM compiler, which outputs the object files that are then given to a linker. Static Java compilers do the same thing with Java bytecode. Java JIT compilers built into Java VMs translate Java bytecode to machine code while the program is running.
So compilation is just the act of translating from one source format to another (e.g., raw source code to machine code, or raw source code to bytecode, or bytecode to machine code).
> In general, I have a very vague understanding of these concept.s I don't understand the basics of how compile time and run time works in D language, it wasn't really explained in the book so when I see terms like 'compile time' and 'run time' I only have a very vague idea of what these things mean and how the process works for D language when compared to other high level languages.
Anything that happens at compile time means it happens while the compiler is translating the source. Anything that happens at run time happens while the compiled program is running.
So take this example:
uint fourcc(char a, char b, char c, char d)
{
return (a << 0) | (b << 8) | (c << 16) | (d << 24);
}
// Here, fourcc is evaluated at compile time
enum nv12 = fourcc('N', 'V', '1', '2');
void main()
{
writeln(nv12);
// Here, fourcc is evaluated at runtime
writeln(fourcc('Y', 'V', '1', '2'));
}
When the compiler is processing this source code, it encounters the declaration of nv12
. Since this is an enum
, it's a compile-time constant that cannot be changed at run time. That means that any value used to initialize it must also be known at compile time. One way to do that would be to use a literal, but in this case it's initialized with a call to the fourcc
function. So the compiler evaluates the fourcc function and uses the result as the initializer of nv12
.
In other words, the end result is just the same as if I had written enum nv12 = 842094158
.
The second call to fourcc
in the main function is not in a compile-time context, so it does not happen at compile time. It happens at run time, i.e., when you double click the executable that the compiler and linker generated (or type its name on the command line).
The general rule is: if a function call is in a context such that it must be evaluated at compile time, then the compiler will evaluate it. Otherwise, it's a normal run-time evaluation.