Interop with iOS OTOH is a breeze, some of the APIs may require newer Swift Library Evolution ABI (direct calls to Swift exprots, without going through C/objC) but .NET is getting it in .NET 9 (the first and only platform to have it at the moment of release).
If the language of the non-standard, deliberately ES262-incompatible NodeJS programming system (and GraalJS, for that matter) is called "JS" without anyone batting an eye—which it does—it's pretty silly to insist the language of Android isn't Java.
That said, you really need to write a bunch of boiler-plate to implement useful things in java-like paradigms in the library today. Just as an example, I wrote up a sane windows _getcwd() stub and it's like 30 lines to implement correctly (properly freeing the buffer when I'm down with it)
My pet project is to see if I can write automatic stubs around calls based on published API info and sources, so that at least some of that platform binding lift isn't just for those with non-trivial knowledge of C. Well, that's the hope anyways.
1. Pointers to the same (and not just references to objects).
2. Unions (via explicit-layout structs)
3. Function pointers.
4. C-style varargs.
To be fair, not all of these have been exposed in C# historically even though CLR had them all along. Most notably, unmanaged function pointers took over 20 years. And since most people look at CLR through the prism of C#, they aren't necessarily aware of these features.
Still, one way or the other, we're at the point where pretty much any C program can be transpiled to C# in a one-to-one mapping of almost every construct (setjmp/longjmp has to be emulated with exceptions), and a very similar performance profile of the resulting code.
5. Stackalloc (C alloca), fixed buffers in structs and inline arrays
6. ref T and Span<T>, which act just like &mut T and &mut [T] in Rust (with the same syntax). They are used in both advanced and most basic APIs alike to provide zero-cost wrapping and/or slicing of arbitrary memory (managed heap, stack, NativeMemory.Alloc'd)
e.g. You can receive byte* and length from FFI and construct a (ReadOnly)Span<byte> from them. That span then can be passed to almost every method that used to work with arrays only during .NET Framework days.
It's a shame really that msft stewardship of the .net/clr was so lacking. Of all the modern virtual machine clr us pretty much up there
It's too bad that this vision was never fully realized - in part, because .NET was not open enough originally, but also because of internal divisions in Microsoft itself. If it did, we could have had the equivalent of both LLVM and WebAssembly much, much earlier.
Also why we got WinRT being like .NET, but with COM and C++, with .NET Native being a complete difference compiler toolchain, as he got hold of the Windows reigns.
We just have to go back in time and see all those Visual Studio.NET shows on surviving documents, or how Ext-VOS (what became .NET) was being done at MSR.
We could have had something like Android, Inferno/Limbo in terms of .NET usage across the Windows layers, but it always bumps into the love for COM and C++, which incendently is how many Longhorn ideas were remade in Vista and continues to this day, using COM instead of .NET.
So once they actually settle on a design (which they seem to have closed on quite a lot in the last couple of years), it might not take that long to happen.
However, I am a little concerned about the heavy emphasis on library unloading in the JEP. Unloading is famously fraught and unsafe for wide swaths of common libraries ... or maybe I'm overfitting due to recent trauma[1] and everything will be fine.
1. https://gist.github.com/thomcc/8c4a8003cf1a282949a539e899cb4...
But the ugliness of JNI stopped me. Then I tried FFI in Java 21, with jextract it was amazing.
I wasn't aware of FFI at first, but the finalized version of virtual threads made me check the Java release notes.