| > But Java can be embedded in native code or embed native code. It has a specified FFI in both directions. Most languages have an FFI, but I am talking specifically about the C ABI and the platform calling convention; or more specifically, about starting from scratch, and what is necessary to do from there until your code can finally run. Anything more complex than the C ABI is what makes people say there is a runtime. It's some layer between your code and the other language's code, inserted there by your language. There's usually no way to remove it, and if there is, it severely limits the language features you can use. > What "starts" Rust's garbage collector? Nothing; it doesn't start unless the function itself wants to start one, and the function can choose which one to start, through your code (rather than what the language's required runtime provides). > A Java program can easily expose any method via the C ABI to be called directly if the process has been started from Java In that case, the runtime has already been started, and is being reused. > Going the other way, i.e. embedding Java in a C program, is somewhat more involved That part is the most important part, and is generally why people say Rust has a minimal runtime; it can be embedded with very little setup. The code you write starts executing almost immediately. Java calling C may add a management layer on Java's side, but C/C++/Rust/Zig/etc need very little (hence, minimal runtime). |
But Rust (or Zig, or C++ for that matter) don't use the C ABI, either, except for specifically annotated functions.
> In that case, the runtime has already been started, and is being reused.
True, but I'm trying to say that the notion of "starting" the runtime (or the GC for that matter) is not really well-defined. HotSpot does need to be "started", but, say, Graal Native Image, which is sort of an AOT-compiled, statically linked JVM, isn't really "started".
> Java calling C may add a management layer on Java's side, but C/C++/Rust/Zig/etc need very little (hence, minimal runtime).
In some implementations of Java this may be the case in some situations, yes. I would go further and say that that's the typical case, i.e. if you want to embed the stock HotSpot, you will need to call some initialisation functions.
If that's what's meant by "runtime", then it's mostly correct, but it's more an implementation detail of HotSpot. Even without it there will remain more important differences between C++/Zig/Rust/C and Java, and this matter of "runtime" is not the most interesting aspect. For example, that Java is usually compiled JIT and Rust is usually compiled AOT is a bigger and more interesting difference.