On Mon, Jun 10, 2019 at 12:04 AM eglue <atdi...@gmail.com> wrote:

> This is great, Alex, thanks. (Sorry, I deleted from underneath you and
> reposted to fix the title before I saw your reply...)
>
> The latter option, writing interfaces and classes in Java and calling w/
> the glue code is a great option.
>
> However one big motivator for people moving from Java to langs like Scala
> and Kotlin is being able to implement those bean/record types, eg, with
> such little fanfare & boilerplate (eg in Clojure, using defrecord is so
> concise).
>

The problem with wanting the Clojure-y version from Java is that those
interfaces are generic and weird from the Java side. So either you get
bean-like code familiar to Java users or generic collection/keyword
interfaces that will be weird to use from Java. I heard your goal as "be
friendly from Java", which means, making bean-like interfaces. On the
Clojure side, it's pretty easy to macro-ize the creation of those over
defrecords or whatever, so it could still be  a lot less macro work, just
depends how far you want to go with it. You don't get all the benefits of
Clojure from Java; you have to be in Clojure for the many related design
decisions to compound together. There's no magic solution to that (other
than "just use Clojure" :).


> And you can sometimes end up with a handful of these, so the 'glue code'
> isn't quite so small. Also gen-class and definterface I find similarly
> nice.
>

I find the glue code is actually small in practice (I've done a couple of
real systems this way). This particular example is a little weird because
it's just making a domain object, but generally you're writing the glue to
provide a factory method for a facade. Below the facade, the Clojure code
can make new objects just fine, so you're staying in Clojure for the rest
of it.


> I wonder if there's a path to improve what you're calling option #2.
> Specifically the needing to AOT compile *everything*. It seems I should
> only have to AOT/precompile the surface area that my Java consumer wants to
> link with. At runtime perhaps there'd be some creative way to leave out the
> AOT classes (which would just have been used for static-time compiling) and
> when the JVM tries to load those classes some agent could interject and do
> the dynamic Clojure loading?
>

Seems like you're taking the hardest path and trying to make it harder. I
just don't see the point in running at this one, sorry. My experience is
that the approach above works great and has none of these issues.


>
>
> On Sunday, June 9, 2019 at 11:21:28 PM UTC-5, Alex Miller wrote:
>>
>> Looks like the title for this is backwards if I understand the intent,
>> should be calling Clojure from Java, right?
>>
>> Java code is going to invoke methods on classes (that's all it knows how
>> to do). You have several options:
>>
>> 1) Use the Clojure Java API to invoke the Clojure runtime - here you're
>> leveraging the Clojure runtime's Java impl core to call into Clojure (Stu's
>> example)
>> 2) Use protocols, records, and/or genclass to actually produce Java
>> classes (your example, I think).
>> 3) Define your interface as a set of Java interfaces. Implement this
>> interface in Clojure. You will need a small amount of glue code to provide
>> the API impl (some kind of a factory to give you the impl of the Java
>> interface - either written in Java or using #1).
>>
>> #1 is straightforward but tedious - it's really only worthwhile if you
>> have a small amount of this code and hide the use of it.
>> #2 has significant downsides - needing to compile everything, all methods
>> are just going to take/return Java Objects, no javadoc on apis,  etc.
>> #3 has advantages in all those areas. You write your Java interface where
>> you can best write it ... in Java (with Javadoc, and Java interfaces, and
>> all the niceties Java users want). IDEs can autocomplete on the Java
>> interfaces. You don't have to AOT - factories can reify or load protocol
>> instances as needed as they return objects. You can even reload internal
>> vars with a connected REPL without restarting the app.
>>
>> The last does take a bit of planning to set up - you need API code (in
>> Java), and Clojure code that relies on that Java code. lein makes it pretty
>> trivial to put those in one project and compile in that order.
>>
>> I pushed an example up here:
>>
>> https://github.com/puredanger/clojure-from-java
>>
>> It defines a Java interface (java/cfj/Event.java
>> <https://github.com/puredanger/clojure-from-java/blob/master/java/cfj/Event.java>),
>> a static helper to hook the Clojure (java/cfj/Support.java
>> <https://github.com/puredanger/clojure-from-java/blob/master/java/cfj/Support.java>),
>> which uses the Clojure Java API to load the Clojure instance in
>> clj/core/cfj.clj
>> <https://github.com/puredanger/clojure-from-java/blob/master/src/cfj/core.clj>.
>> Just `lein uberjar` and you're done. Use the Support API from Java as any
>> other Java class. No AOT required.
>>
>>
>>
>> On Sunday, June 9, 2019 at 9:53:56 PM UTC-5, eglue wrote:
>>>
>>> I've been stalking Clojure for a while but now doing it professionally
>>> full-time (woo hoo!).
>>>
>>> I saw a Stuart Halloway tweet responding to someone who'd found it a
>>> "soul-crushing, miserable experience."
>>>
>>> I had a similar miserable experience and figured it was just me, but am
>>> now suspecting that's not the case. (Happy to be shown the light however.)
>>>
>>> Stuart H posted https://github.com/stuarthalloway/clojure-from-java
>>> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fstuarthalloway%2Fclojure-from-java&sa=D&sntz=1&usg=AFQjCNFxHASS9MQ07WZ5St1GE9g1WckHFg>
>>>  to
>>> demonstrate the ease of Java consuming Clojure, but I find it far more
>>> important to be able to *compile* Java against Clojure interfaces not
>>> invoke it dynamically from Java....because dynamic invocation from Java is
>>> unwieldy to the point of it being a likely deal breaker for any Java shop.
>>> Dynamically loading classes and invoking methods.... c'mon, no one's going
>>> to ask their Java devs to do this.
>>>
>>> If Clojure doesn't have a good compile-time consumption story for Java
>>> consumers, I think that's a loss. (Even if it is just providing better docs
>>> or archetype/bootstrap examples in this regard.) Because otherwise Java
>>> code bases around the world could be eaten away by (compiled) Clojure from
>>> the inside out, giving Java dev teams enough time to be overtaken by the
>>> miracle that is Clojure.
>>>
>>> Inspired by Stuart's example, I was successful in putting together a
>>> quick build to achieve this ideal:
>>> https://github.com/atdixon/clojure-from-java
>>> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fatdixon%2Fclojure-from-java&sa=D&sntz=1&usg=AFQjCNG0DEccFtsm0Norw4jQ_qw-dezdZw>
>>>
>>> However, I have a few open questions:
>>>
>>> - when I tried to AOT only the public-facing clojure code that I needed
>>> to compile against, I found out at runtime that this wasn't going to work.
>>> Dynamic clojure code was loading my same types into DynamicClassLoader and
>>> when my statically-compiled, root-class-loaded code was getting executed
>>> the ClassCastExceptions of course were flying. So am I right to think that
>>> you have to AOT everything in order to do this right?
>>> - IDE support (for me, Cursive) "works" but is non-ideal; you have to
>>> manually compile the dependee/Clojure jar, then Cursive will let you
>>> execute Java code against the manually aot-compiled Clojure code
>>> - AOT producing generics/generic types doens't seem to be part of any of
>>> this... is this a lacuna in the Clojure AOT space, are there libs that can
>>> help here?
>>>
>>> This story ^^, if made easier, seems to me would boost Clojure adoption
>>> in Java/JVM shops.
>>>
>>> What am I missing?
>>>
>>>
>>> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "Clojure" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/clojure/aejqMwraPk8/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> clojure+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/clojure/07753636-3414-481f-8836-763ca85675ce%40googlegroups.com
> <https://groups.google.com/d/msgid/clojure/07753636-3414-481f-8836-763ca85675ce%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/CAOdgdgzCFd3oSSyq0VNOkDftdohgPhmKh1T8uTdCXxC0uhzKnw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to