Fork me on GitHub
#clojure
<
2023-12-01
>
Dallas Surewood17:12:50

Is there a good resource for learning java interop best practices? I'm a bit confused how to best use a java library while staying as functional as possible

p-himik17:12:14

Note that staying as functional is possible can easily be detrimental. As a slightly contrived example, suppose that some Java method returns an ArrayList that you need to map over and pass to some other method that accepts only instances of ArrayList. In such a case using Clojure's map is unlikely to be worth it and you might mutate the list in place via dotimes or something like that. I don't know whether there's a document outlining the "best practices", but there's a page in the official reference: https://clojure.org/reference/java_interop

seancorfield17:12:51

There's also this "nuts'n'bolts" page on http://clojure-doc.org https://clojure-doc.org/articles/language/interop/ (PRs welcome to improve it). It's not about best practices but it's a bit more extensive than the official reference. A lot is also going to depend on the specific Java library. Can you be a bit more specific about your question?

Dallas Surewood18:12:52

I think in general I'm just wondering how I should handle stateful java objects, like servers. Should I be putting the whole java object in an atom? How can I keep track of what the internal state of the server is?

seancorfield18:12:51

You mean like starting/stopping a Jetty server? You can do that in -main or via something like Component. See https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L202 onward for example.

seancorfield18:12:07

All programs that do anything useful have some stateful effects, even if it's only at the boundaries -- functional core, imperative shell -- but most programs have stateful effects scattered across them (e.g., database operations). That's not really specific to Java interop.

Dallas Surewood19:12:05

Yeah, I'm not saying it's specific to java interop. It doesn't have to be a server either, I just mean what's a general way to handle mutable state with java interop? For instance, Clojure has atoms and swap and different ways to minimize mutation bugs. But if I have instantiated a java object, is there a way to attach a watch to one of its public variables?

seancorfield20:12:07

For that specific question, no, you can't watch a Java object (and they're unlikely to have public variables anyway, just public methods). There is no "general way to handle mutable state with Java interop". You really have to deal with it on a specific case-by-case basis, depending on the API the Java code gives you and the context of how you're using it. Sometimes hiding that mutability is worthwhile, mostly it isn't. Like I said tho', you need to ask a specific question about some specific Java object(s) that you're working with. There's no one-size-fits-all here.

timo08:12:06

afaik there will be a lot of changes for interop coming with the next clj-release

seancorfield17:12:50

Yes, 1.12 Alpha 6 will have some big improvements around functional interfaces and array types.

isak17:12:00

Is this a bug with type hinting?

markaddleman17:12:09

Is this cursive? I have noticed that Cursive will show warnings that do not result in Clojure compiler warnings

markaddleman17:12:41

I have found it useful to ensure that *warn-on-reflection* is set to true

👍 1
isak17:12:38

Yea it is

isak17:12:21

This also worked:

markaddleman17:12:27

As I look closer at your code, I see you are type hinting an array. I have found that Cursive does not understand the array type hint but the Clojure compiler does

markaddleman17:12:59

Interesting. I expected the problem to be the array type hint

markaddleman17:12:23

You may want to report this in #C0744GXCJ

isak17:12:41

Hmm for me the arrays have worked in cursive

markaddleman17:12:15

Makes me want to review my situation. Thanks!

isak17:12:56

I'll report back when I have some runnable code and can see if I get a reflection warning in the log (so we will know if it is just Cursive)

hiredman17:12:49

You should type hint the names you are binding not the values being bound

hiredman17:12:03

I am surprised that first Jedis typehint doesn't throw an exception, there is no way to attach metadata to nil

isak17:12:01

Oh yea I fixed that

isak18:12:53

Ok I can confirm it is a Cursive problem (it is not reported via *warn-on-reflection*). I'll file a bug.