Specifically, I'm talking more about C++ and Rust than others. I don't understand how C++ has a "runtime" in the sense that Java and C# have a runtime--while Java and C# run on top of a virtual machine with its own encapsulated abstractions and such, I don't get how C++ might have one.
Take virtual tables for C++, for example. Do we consider dynamic_cast<type>
a part of C++'s runtime functionality or are we talking about C++'s structure for vtables in general? Can we consider new
and delete
a part of the C++ runtime environment? What exactly constitutes a runtime?
For example, here we have a Rust article on its own runtime, which describes it as :
The Rust runtime can be viewed as a collection of code which enables services like I/O, task spawning, TLS, etc. It's essentially an ephemeral collection of objects which enable programs to perform common tasks more easily.
But is this not the function of a standard library or language features, not an actual runtime? What constitutes this very thin but existent runtime? Even Bjarne expresses his thoughts that C++ has "zero-overhead abstraction", but if C++ has a runtime, does this not imply that C++ does indeed have some sort of "backend" code to orchestrate its own very light but still existent abstractions?
TL;DR: What is a runtime and/or runtime environment in the context of languages like C++ and Rust that have supposedly "zero-overhead" and don't have "heavy" runtimes like Java or C#?
Edit: I suspect that I'm just missing something about semantics here...
C++ requires a few things that aren't required in something like C.
For example, it typically involves some overhead for exception handling. Although it may not be strictly required, most systems have at least a tiny bit of a top-level exception handler to tell you that the program shut down if an exception was thrown but not caught anywhere.
It's open to question whether it qualifies as "runtime environment", but the compiler also generates code to search up the stack and find a handler for a particular exception when one is thrown.
On one hand, this is exceptionally tiny (bordering on negligible) compared to something like a complete JVM. On the other hand, it's quite large and complex relative to what happens by default in something like a JVM or Microsoft's CLR.
As to zero overhead...well, it depends a bit on your viewpoint. Exception handling code can normally be moved out of the main stream of the code, so it doesn't impose any overhead in terms of execution speed as long as no exception is thrown. It does, however, require extra code so there can be (often is) quite a bit of overhead if you look at executable sizes. Just for example, doing a quick look at a "hello world" program, it looks like turning off exception handling reduces the executable size by about 2 kilobytes with VC++.
Admittedly, 2K isn't a whole lot of extra code--on the other hand, that's just what's added to essentially the most trivial program humanly possible. For a program that actually does something, it's undoubtedly more.
In the end, it's not enough that most people really have a reason to care, but it does exist nonetheless.
As to how this is handled, it involves a combination of code that's linked in from the standard library and code generated by the compiler (but the exact details vary with the implementation--for example, most 32-bit Windows compilers used Microsoft's Structured Exception Handling (in which case the operating system provides part of the code) but for 64-bit Windows, I believe all of them deal with exception handling on their own (which increases executable sizes more, but reduces overhead in terms of speed).