The Case for Rust (in the base system)

In userspace, sure. I mean what's Android.
Still reliant on the NDK for many of its underlying libraries.

Just look at any substantial project and you will see a tonne of jni and native C/C++ libraries. Turns out Java wasn't a better tool.

With the introduction of C/C++ NativeActivity and Kotlyn, it seems that Java usage is even becoming quite legacy now in the Android ecosystem.
 
IMO that's just a symptom of Java not reaching far enough down. Hence stuff like Rust and Golang.
Indeed. And C reaching further still (including deep into the JVM that is primarily written in it).

Plus we have another issue. Calling Rust from Java is quite tricky. Calling Java from Rust needs to go through C anyway. Hence Rust Bindings to JNI. Another use-case that this completely crap guide overlooks. Binding against VM languages written in C (or anything else).
 
You seem intent on muddying these things. Rust and goes as far as C does before both of them have to bang rocks together to run an opcode.

Rust from Java should be as easy as a C JNI. IIRC Rust should be mostly indistinguishable from any other C library. Java from Rust is going to be difficult to do in order to reconcile memory models. Directions matter.
 
Just look at any substantial project and you will see a tonne of jni and native C/C++ libraries. Turns out Java wasn't a better tool.
I work on plenty of substantial projects that are pure Java. They're not open source.

Kotlin is just the latest Scala, Clojure, Groovy, etc. Some lame semi "functional" or "declarative" language bolted on to the JVM badly. Hard pass.
 
You seem intent on muddying these things. Rust and goes as far as C does before both of them have to bang rocks together to run an opcode.
Its actually the mud you want to focus on more to understand Rust's limitations. With C you can tap into the underlying OS directly, using its C APIs. opcodes are easy, it is the muddy layers in between that is complex to interface with if you are using the wrong language the underlying OS API was written for. This is why Rust's crates.io is filled with C bindings rather than tapping into i.e inline assembly directly.

In short, the depths of the OS internals are out of reach unless Rust can consume C headers.

Rust from Java should be as easy as a C JNI.
No, Rust has the same complexity as C++ does with JNI. One of the main use-cases of C is because languages can bind against it easily. With C++ and Rust you have no stable ABI for one. Passing an std::string or equivalent is also no good.

With Rust you will need to do the same as C++. That is expose your *entire* API through extern "C" "unmangled" function wrappers. This comes with numerous limitations too.

Java from Rust is going to be difficult to do in order to reconcile memory models. Directions matter.
Yep, hence why I stated both directions. Rust has no native JNI of its own and never can, so is at a big disadvantage to C (and close supersets) there.
 
You're telling me Rust doesn't access libc unless it's through "mud"? Maybe the problem is what is this "mud" and how is it different than a "shim" or a "wrapper", or "glue." Is "mud" just a "shim" for things people don't like?
 
You're telling me Rust doesn't access libc unless it's through "mud"?
Rust indeed has some fairly minor inbuilt "mud" for libc. But when was the last time you have been able to write a large program using *just* libc?

So you would need more mud for any dependency you use. Gtk, SDL, oci8, sqlite, libevent, etc, etc.

A little bit of mud is fine but it all starts to build up and ultimately why Rust solutions pull in a shedload of dependencies to do trivial things. It isn't about avoiding reinventing the wheel anymore; it is about covering the wheel in mud so that Rust can use it.

A more specific example, if you wanted to use Rust to improve the i.e JVM garbage collector how would you even begin? Sure, you can execute opcodes. You can access libc. But how would you actually start to add code that integrates with the existing (monstrous) JVM GC code? You would need to basically expose everything in it to Rust through some substantial boilerplate. If this isn't mud, I don't know what is.

Maybe the problem is what is this "mud" and how is it different than a "shim" or a "wrapper", or "glue."
No difference. Its all the same. Bindings, whether fat or thin.

Is "mud" just a "shim" for things people don't like?
Absolutely. I don't think anyone likes shims, wrappers or glue. Especially when they tend to rot and go unmaintained quite often.

Don't get me wrong. If everything was written in Rust rather than C and the roles were reversed, absolutely I would find people trying to use C to be completely mad. But unfortunately this is not what happened.

The Rust team do acknowledge this interoperability issue higher up the chain. Thus why projects such as this exist. However it is just a little silly to see the Rust community (ignoring the noisy reddit kids or students who don't know better) trying to pretend that this problem doesn't exist.
 
I work on plenty of substantial projects that are pure Java. They're not open source.
On Android? That is surprising.

Certainly for large scale enterprise systems, Java is still going strong. In many ways this is one of the use-cases where it can be "pure" because it doesn't need to interop with lower level systems (by design!). Pretty much just files and sockets (as a gross oversimplification ;)).

Kotlin is just the latest Scala, Clojure, Groovy, etc. Some lame semi "functional" or "declarative" language bolted on to the JVM badly. Hard pass.
I have never actually tried it. Frankly the java-like build systems scare me off before I even get to the languages XD
 
On Android? That is surprising.
Nope. GUI programming in Java is a joke. Then again, looking at things like Electron, maybe it's not so bad.

I have never actually tried it. Frankly the java-like build systems scare me off before I even get to the languages XD
Yeah, they're a nightmare. One of the original sins of Java was to break the invariant that 1 source file = 1 compiled file. It was a side effect of trying to simplify by eliminating header files. That made it apparently impossible to write a reasonable build tool because javac foo.java can wind up generating any number of .class files.

There's also a stunning level of ignorance among "senior" Java programmers. You wouldn't believe how many times I've had trouble explaining how to build a simple test case I'd written in pure core Java by running
Code:
javac MyTest.java
java -cp . MyTest

EDIT: And... I screwed up the build/run commands 🤣 Maybe I'm not as smart as I think I am.
 
Yeah, they're a nightmare. One of the original sins of Java was to break the invariant that 1 source file = 1 compiled file. It was a side effect of trying to simplify by eliminating header files. That made it apparently impossible to write a reasonable build tool
I see. Yep, one I used to run into was that "anonymous inner classes" generate extra .class files that the build tool doesn't know about (and can't infer). It makes it a pain to even use Makefiles with it. That said, computers are so fast now and Java compiles relatively quickly that I would be tempted to still use Makefiles and just compile up the whole module per change, keeping the build system simple (probably why I am never invited to join Java projects ;)).
You wouldn't believe how many times I've had trouble explaining how to build a simple test case I'd written in pure core Java by running
Heh, for some (annoyingly veteran) developers, If you know more than "Just click the green "play" button" to build. You are basically a wizard.
 
  • Like
Reactions: mer
I see. Yep, one I used to run into was that "anonymous inner classes" generate extra .class files that the build tool doesn't know about (and can't infer).
Yep, but that's not the only problem. Consider the following trivial Java classes

Foo.java
Java:
class Foo{public static void main(String[] args){Bar.mess();}}

Bar.java
Java:
class Bar{static void mess(){System.out.println("Hello, world!");}}

Now if you run javac Foo.java you'll notice that both Bar.class and Foo.class are generated. If you compile Bar.java first, its .class file will just be used without updating it. Thus the objects generated by compilation depend on the order in which things are compiled!

This makes javac both a compiler and primitive build tool. The intention was good. There were a lot of ugly pre-processor mazes in the '90s that caused many, many hard to debug problems. However, this violation of the principle to do only one thing and do it well makes it impossible to come up with a nice clean DAG for Java builds. Hence the proliferation of monstrous and abstruse build systems for it.
 
Back
Top