3 ms·
> with or without a runtime This is the point - no, you actually DON'T get all the benefits of a runtime. C# famously, and extensively, used runtime code gener
by consteval 2y ago
> with or without a runtime
This is the point - no, you actually DON'T get all the benefits of a runtime. C# famously, and extensively, used runtime code generation. Not possible in Rust, kind of possible in C++.
> Necessitating certain things happen at runtime
Not how it works. The language is still compiled. You can 100% implement a borrow checker for C#, there's nothing stopping anyone. It's just not what they want to do.
For example, C++ and C are BOTH compiled languages. But C++ is able to verify the type of various operations at compile-time, but C has to wait until runtime. For example, C's qsort takes void pointers and then you cast and dereference them at runtime. In C++, this is physically baked into the type of function template std::sort.
But they're both compiled languages with no runtime. But because C++ has a much more complete type system, it can do those things at compile-time while C cannot.
Another example: while C# has polymorphized generics, it checks them at compile time! The generics are not monomorphized like C++ or Rust, which allows smaller linked libraries that you can load and use at runtime, which is not possible in C++ templates or Rust generics. The trade-off is then that generics can't be checked until runtime - but actually no. The C# compiler will go out of its way to check generics when it can and will fail if they don't meet the type constraints, just like C++ or Rust.
Rust is very powerful, BUT:
1. It doesn't cover all the usecases of more powerful languages with rich runtimes like C# or Java
2. Using async rust, which is typically a requirement for webdev, requires a runtime anyway.
- neonsunset 2y ago> Another example: while C# has polymorphized generics, it checks them at compile time! The generics are not monomorphized like C++ or Rust, which allows smaller linked libraries that you can load and use at runtime, which is not possible in C++ templates or Rust generics. The trade-off is then that generics can't be checked until runtime - but actually no. The C# compiler will go out of its way to check generics when it can and will fail if they don't meet the type constraints, just like C++ or Rust. Generics are not monomorphized at bytecode level, but whenever generic argument is a struct, the methods and types that have it are monomorphized at the stage of compiling to machine code, be it with JIT or ILC. This is identical to Rust, and is why C# has "zero-cost" abstractions. Method bodies and types for class-type generic arguments are indeed shared however. Dispatch on generic constraints is still quite efficient in that case, even if no longer zero-cost (unless the compiler is able to see the exact type and inline such calls, or emit a guarded devirtualized fast-path when compiled by JIT, or prove that only few types implement a particular interface or subclass a specific parent when compiled by NativeAOT).