3 ms·
Clojure Java interop has been pretty painless in my experience. https://clojure.org/reference/java_interop https://clojure.org/reference/java_interop It's pre
by grzm 6y ago
Clojure Java interop has been pretty painless in my experience.
https://clojure.org/reference/java_interop https://clojure.org/reference/java_interop
It's pretty easy to translate things like
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
//...
Instant nowInstant = Instant.now();
Instant fiveMinutesAgo = nowInstant.minus(Duration.ofMinutes(5));
Date nowDate = Date.from(nowInstant);
to
(import '(java.time Duration Instant))
(import '(java.util Date))
;; static method call with / (slash)
(def now-instant (Instant/now))
;; instance method call with dot. First arg is the instance
(def five-minutes-ago (.minus now-instant (Duration/ofMinutes 5))
(def now-date (Date/from now-instant))
Implementing interfaces and extending classes are a bit more involved, but I haven't had to do much of that in my experience, and when I have had to, that's been pretty good, too.
Here's an example implementing the AWS Lambda RequestStreamHandler interface
https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestStreamHandler.java https://github.com/aws/aws-lambda-java-libs/blob/master/aws-...
(ns com.example.hn.handler
(:gen-class
:implements [com.amazonaws.services.lambda.runtime.RequestStreamHandler])
(:require
[clojure.java.io :as io]))
;; implement the RequestStreamHandler handleRequest method
(defn -handleRequest
"echoes request"
[_ input-stream output-stream _context]
(let [w (io/writer output-stream)
event (slurp input-stream)]
(-> w
(.write event)
(.flush))))
That's probably shorter than the equivalent Java implementation.
- Scarbutt 6y agoShowcasing Clojure's Java interop with the java.time library is IMO pretty disingenuous. That's a pretty good modern library with a great API conformed completely of immutable classes, most Java libs are not like that.
- grzm 6y agoI can only show things I use, and these are things I do every day. (I also wanted a succinct example to post on the forum that people might be familiar with.) Please do share counter examples, as I'm genuinely interested. One of the more complicated things I've had to do was parseBest as part of DateTimeFormatter, which takes a TemporalQuery as an argument. It has a solution like this: https://clojurians-log.clojureverse.org/clojure/2019-09-06/1567785740.204500 https://clojurians-log.clojureverse.org/clojure/2019-09-06/1... I've also worked with JDBC libraries to wrap driver-specific features. JDBC drivers have been around for a long time, and driver-specific stuff can vary in how well it's designed. I've also used jna through Java from Clojure when I was just starting out, which wasn't all that hard for a newbie to the language. From your comments in other Clojure-related threads we've participated in, it sounds like your experience is much different from mine, but often lacks in specific examples. Without seeing those, it's hard to know what you're describing. If you think Clojure isn't the bees knees, that's perfectly fine. I think readers would benefit from knowing specifics of what you've found frustrating.
- deleted 6y ago[deleted]
- Scarbutt 6y agoThere's no good way to extend abstract classes. If you're using proxy, you pay a large performance penalty, and you can't call protected superclass methods or access protected superclass fields without using reflection. gen-class is a truly awful thing to use. Even when type hinted, defrecord fields all have type Object. primitive type hinting, and corners like the type hinting in deftype/reify (where you have to either type hint everything or nothing) Having to type hint with ^"[Lcom.example.project.package.Class;" is foul. No niceties like SAM conversion, No integration with java.util.function interfaces.
- grzm 6y agoThanks for the examples! There are some things that aren't as easy. And sometimes it's a better choice to drop into Java to provide a shim between the package you're interacting with and Clojure to make the interop easier, or when performance matters. Regarding hinting for defrecord fields and deftype/reify, do you have references where this has been a problem for you? It's not something I've run into, but that's just my experience. As for java.util.function interfaces, I just did this within the past couple of weeks, which worked for my use case: defn ^java.util.function.Function as-function [f] (reify java.util.function.Function (apply [this arg] (f arg)))) For SAM conversions in general, there's https://github.com/ajoberstar/ike.cljj https://github.com/ajoberstar/ike.cljj . I haven't used it myself, but perhaps the pattern used there would work in you. It sounds like what you've worked on has been relatively performance sensitive, which can definitely a thing. So perhaps some of these interop suggestions won't work for you. Again, thanks for taking the time to be more explicit about what you've found frustrating.
- skissane 6y agoI wonder, are the Clojure developers planning to fix these deficiencies? Most or all of them are things which could be fixed with some work.