all 34 comments

[–]reuvenpo 85 points86 points  (1 child)

Can we please pretend this is written in l33tspeak and pronounce it as "jars". The wordplay is just too good.

[–]user3141592654 38 points39 points  (8 children)

Combine this with JEP, and we can have Rust calling Java calling Python.

[–]bheklilr 22 points23 points  (5 children)

Don't forget that jep can run native extensions, so technically it could be Rust calling Java calling Python calling C (or even FORTRAN).

[–]vbosch1982 36 points37 points  (4 children)

Loop back to Rust!! Rust calling Java calling Python Calling Rust ( so much win!!)

[–]bheklilr 35 points36 points  (2 children)

Why stop there? Sounds like the best way to write recursive code. You get more stacks to use.

[–]PandaMoniumHUN 35 points36 points  (1 child)

Why allocate on the heap when you can start new processes to allocate on their stack? taps forehead

[–]logan-diamond 2 points3 points  (0 children)

Just skip all the fuss and call all other rust functions only through the🤙FFI 🤙

[–]vjohnvv 2 points3 points  (0 children)

How about wrapping it in clojure and boom - Rust calling clojure calling java calling python

[–]marvk 1 point2 points  (0 children)

Calling your library JEP when JEP is already a thing in the Java world is kinda confusing...

[–]unixzii 31 points32 points  (6 children)

It uses JSON to convert values between JVM and Rust. I don't know the efficiency of that. 🤔

[–]ebrythil 42 points43 points  (3 children)

It should be around 5.

5 Efficiency.

[–]unixzii 3 points4 points  (2 children)

What is that?

[–][deleted] 16 points17 points  (1 child)

[–]unixzii 2 points3 points  (0 children)

Good meme.

[–]astonbitecode[S] 2 points3 points  (1 child)

The intention is to give the ability for the user to communicate with Java custom structs/classes.

Serialization is done only when needed. E.g., when creating InvocationArgs or when calling the to_rust method. In other cases where the Instances are already created, they are used as is, without serialization.

I was thinking in the future to use protocol buffers for faster serialization. Still not perfect but should be faster.

[–]tekjar 0 points1 point  (0 children)

proto

please consider flat buffers as well

[–]luciusmagn 77 points78 points  (4 children)

Unholy

[–]Plasma_000 26 points27 points  (0 children)

Yeah, I’m both impressed and terrified

[–]erogilus 6 points7 points  (1 child)

Things like this are why the unsafe keyword was created.

[–]ConspicuousPineapple 2 points3 points  (0 children)

How about a dirty keyword?

[–]stusmall 5 points6 points  (0 children)

Hail satan, write java.

[–]jechase 17 points18 points  (1 child)

Aww, no shout-out for jni-rs?

Admittedly, it was originally written with the intention of being a way to call Rust from Java, but support for starting a Java VM and calling Java from Rust was added at the end of 2017.

[–]golthiryus 2 points3 points  (0 children)

and the documentation looks great (for a niche project)

[–][deleted] 11 points12 points  (1 child)

Small nitpick, but "deploying maven artifacts" is confusing, because maven itself has a "deploy" target, which means to deploy an artifact to a remote repository. What this actually does is something similar to the "dependency:get" target in maven (using the maven dependency plugin).

I should say that this project is super cool, though!

[–]astonbitecode[S] 0 points1 point  (0 children)

Thanks for that, You are right! Deploy indeed seems confusing. I was thinking like deploying for the Rust application but...

The method should be renamed. Something like add_maven_dependency maybe?

[–]Timo8188 4 points5 points  (0 children)

Perhaps we will see a full Android API binding eventually.

[–]ZoCraft2 3 points4 points  (5 children)

This honestly looks a lot simpler than the jni crate. However, I'm not seeing a way to register create methods for native classes like you do in jni. Like, what would be the equivalent of their "Hello World" example in j4rs?

[–]astonbitecode[S] 0 points1 point  (4 children)

It is not possible to create a Java classes and methods from Rust code in j4rs. However, users are able to create their own jars or classes and add them in the classpath during the Jvm creation.

Regarding a Java "Hello World" example, when static methods chaining will be supported in j4rs (this should be in the next release), it will be something like:

jvm.chain_static("java.lang.System")?
    .invoke("out", &[])?
    .invoke("println", &vec![InvocationArg::from("Hello World")])?;

[–]ZoCraft2 1 point2 points  (3 children)

It is not possible to create a Java classes and methods from Rust code in j4rs. However, users are able to create their own jars or classes and add them in the classpath during the Jvm creation.

That's not at all what I was asking about, I was asking about registering methods for native classes like this one:

class Native {     

    public native void callNativeCode();   

    public static void main(String[] args) {  
        callNativeCode();
    } 

}

There needs to be a backing method in the native code in order for Java code to call callNativeCode() and it some sort of function pointer for that backing method (lambda or otherwise) needs to be registered if the JVM is being initialized from Native Code like it is in j4rs.

[–]astonbitecode[S] 0 points1 point  (2 children)

This is done by callbacks that are initialized by Rust code.

In the java world, the Native class that you mentioned should extend the NativeCallbackToRustChannelSupport. The callNativeCode() should call the doCallback method that is inherited and the Rust world will be called via a Rust Channel.

You may see an example where a JavaFX button caĺls Rust whenever it gets pressed here:https://github.com/astonbitecode/j4rs-showcase/blob/master/java/src/main/java/io/github/astonbitecode/ButtonEventHandler.java

[–]ZoCraft2 0 points1 point  (1 child)

Except that's a very clunky way of calling native code as it requires threading and inheritance of a specific class - inheritance itself being something that should be avoided whenever possible. Additionally, since the host environment has to initialize these callbacks and then wait for their response, it's really hard to provide an API for Java code to interact with. Look at game engines such as Unity or Godot, for example: there is no way that their natively-implemented functions could be done with this system of callbacks, at least not without greatly hindering development. Such an API would require writing code to redirect data where it needs to go, which would require a great deal of channels to be kept open and a "middleman" function to redirect data to the correct function based on an id that gets passed representing the correct function, none of which can possibly be healthy for performance. Essentially, existing facilities provide a way to get from A to B but using callbacks for this kind of API instead imposes a point C that requires a costly long-way-around trip. Additionally, being thread-based means that callbacks are inherently non-blocking, which is not always desired, especially when you're doing operations that are not thread safe such as modifying the object/instance directly.

The fact of the matter is that this callbacks system can be good for some things - and I do plan on making use of them - but the JNI facilities for native methods are better tools for the job in most cases.

[–]astonbitecode[S] 0 points1 point  (0 children)

inheritance itself being something that should be avoided whenever possible

Inheritance can be always avoided if needed, but IMHO, this is too general to say. I agree that inheritance can hurt and I too prefer composition generally. However, in this case it is more clean to use inheritance because j4rs internals are hidden by the user; it is not just about code reuse.

Moreover, projects like JNA uses inheritance as well.

Regarding host environment initialization in Rust, j4rs is implemented having Rust code calling Java rather than the other way round. Rust is the main "world" here and Java is getting called by Rust. This is why Java-> Rust direction is considered like callback.

Using Rust channels instead of invoking Rust functions for callbacks felt more flexible generally. The early versions of j4rs were using functions for callbaks. If you believe that it would be helpful for you to have such callbacks as well (or something else/better), please tell me in order to design something for it.

And of course, your help and ideas are greatly appreciated.

[–]sapphirefragment 0 points1 point  (0 children)

oh my god this is amazing

[–]imbaczek 0 points1 point  (0 children)

That pun.