Fork me on GitHub

Hey guys, I just compiled a build of openjdk called to do some testing. How can I run Clojure, so that it uses the java runtime I just built?


First thing I tried to do was make a shell script. I set JAVA_HOME and echoed it out just fine, but the Clojure repl still indicates I'm using the version installed on my system.


#!/usr/bin/env fish

set JAVA_HOME "/home/main/code/community/wakefield/build/linux-x86_64-server-release/jdk"

/usr/bin/clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version "0.9.0"} cider/cider-nrepl {:mvn/version "0.28.3"} refactor-nrepl/refactor-nrepl {:mvn/version "3.5.2"}} :aliases {:cider/nrepl {:main-opts ["-m" "nrepl.cmdline" "--middleware" "[refactor-nrepl.middleware/wrap-refactor,cider.nrepl/cider-middleware]"]}}}' -M:cider/nrepl


I think clojure only uses JAVA_HOME if JAVA_CMD is not set, so try set JAVA_CMD "$JAVA_HOME/bin/java" after you set JAVA_HOME...


(! 853)-> JAVA_CMD=$OPENJDK8_HOME/bin/java clj
Clojure 1.11.1
user=> (System/getProperty "java.runtime.version")
user=> ^D

Fri Apr 29 17:38:25
(! 854)-> JAVA_CMD=$OPENJDK11_HOME/bin/java clj
Clojure 1.11.1
user=> (System/getProperty "java.runtime.version")
user=> ^D
That said, on my Mac, just setting JAVA_HOME is enough to tell the default installed java executable to use the specified installation -- but that may well not be true for the default java on your system:
Fri Apr 29 17:38:35
(! 855)-> JAVA_HOME=$OPENJDK8_HOME clj
Clojure 1.11.1
user=> (System/getProperty "java.runtime.version")
user=> ^D

Fri Apr 29 17:38:43
(! 856)-> JAVA_HOME=$OPENJDK11_HOME clj
Clojure 1.11.1
user=> (System/getProperty "java.runtime.version")


From the clojure script:

# Find java executable
set +e
JAVA_CMD=${JAVA_CMD:-$(type -p java)}
set -e
if [[ -z "$JAVA_CMD" ]]; then
  if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
    >&2 echo "Couldn't find 'java'. Please set JAVA_HOME."
    exit 1


set JAVA_HOME /home/main/code/community/wakefield/build/linux-x86_64-server-release/jdk

set JAVA_CMD $JAVA_HOME/bin/java

/usr/bin/clojure ... -M:cider/nrepl
still the same result unfortunately


> (System/getProperty "java.runtime.version")


Tried changing my script to bash as well, didn't work.


I don't know about fish as a shell but I'm used to shells where you have to export env vars...


That's easy enough to do with set -x.


Hey it works!


> (System/getProperty "java.runtime.version")


Thanks Sean!


Cool! What are you testing in jdk19?


I'm trying to see what wakefield can do on a wayland backend.

(ns core
  (:import (java.awt Frame)))

Unfortunately this doesn't work.


Oh nice! I didn't recognize the project name Wakefield (but now I remember)

Bart Kleijngeld17:04:13

I'm trying to sell Clojure as the language of choice at work, and I was hoping to get some inspiration from people here :). Hearing from people with experience in Semantic Web, meta-modeling and schema transformation would be particularly useful.

Bart Kleijngeld17:04:26

We're building an (open-source) application which takes as input a data model described by RDF files, and puts out a generated schema of several possible types (Apache AVRO for example, but we want to expand to all sorts things such as SQL schemas). So it gets quite "meta", and we deal with generation of all sorts of data structures from whatever input set of files we may have. We left Java, and are currently trying a functional (FP) approach in Kotlin. It's not too bad, but I'm not happy about a lot of things. I gave Clojure a try in my spare time and I fell in love immediately. Now, I'm trying to make an objective case for why it is more useful for our purposes, and I would love to hear your thoughts. Both in response to what I'm thinking, as any ideas of your own. First of all, I think static typing isn't useful here, but gets in the way. Modeling highly abstract data using types is tricky. It isn't as flexible as a heterogenous map with a spec, and moreover it's hard (if not impossible) to generate classes from data at runtime, as we need to. Of course, you can choose not to model using types, but if that's the route you're taking, I feel you're basically choosing Clojure and maps. Especially since maps in Kotlin are not heterogenous. Furthermore, functional programming in Clojure feels great. You can express yourself very strongly, and there's no hassle with weird syntax, complicated casting of types and noisy syntax (this is my experience in Kotlin). Transforming data has never felt so powerful. Another reason for choosing Clojure is the helpful development workflow using the REPL. Especially when building out data, it can be very useful to check out intermediate results before moving on. With Kotlin, this feedback is not only much slower, but it also requires me to run some main/test function, and worst of all make sure my types are in order (since the intermediate result often has a different type). I've noticed myself being greatly productive in Clojure thanks to this, and I feel that especially if the data gets complex, this is very helpful. Finally, since it's runs on the JVM we can use all sorts of Semantic Web libraries built in Java (like Eclipse's RDF4j) without issues.

Bart Kleijngeld17:04:17

If anyone's stuck with me so far, thanks already :). I would love to know if you think my arguments make sense and are sufficiently objective with regards to the application we're building. Besides feedback on my points above, I would appreciate other input as well. Particularly with regards to the following remarks/questions I'm anticipating from my manager: 1. Sourcing people for Kotlin is doable, but Clojure is an esoteric niche. 2. Isn't Kotlin a good enough choice to warrant continuing to develop in it (note: this project is very much in its infancy) 3. Static types provide a better guarantee for mature software. I don't like the idea of dynamic typing, it feels unsafe.


I think you'll find a surprising percentage of people in the clojure space working with RDF or RDF-like models


maybe crosspost to #rdf for visibility?


rich hickey's talks, especially about Datomic, also reference RDF and the semantic web quite a bit. socializing some of those talks and his ideas might go a long way to convincing people that the language he wrote to scratch his own itch might scratch yours as well

Bart Kleijngeld18:04:10

Thanks 🙂, and didn't know about that channel, so good to know


In my experience, it is best to appeal to people's curiosity.


At least to convince the other engineers. Tell them it's a great opportunity to learn a lot of new concepts. Clojure unlike Kotlin and Scala, really forces you to learn functional programming proper. You also get to learn about metaprogramming proper and explore what makes it so Lisp still hangs around 50 years after its inception, and learn the interactive development workflow it provides.


And the cool thing is, you get to do all that on company's payroll, and there's no risk to the project, you can still use all JVM library, you can still implement some chunks in Java if you need too.


Where I found introducing Clojure was hard, is when your coworkers are not the curious kind who like to learn new stuff. When they enjoy the safe and comfort of familiarity.

Patrick Brown19:04:37

It’s a small point, but namespaced keywords in clojure are the norm and one of the many motivations behind them was RDF. You’ll find many aspects of Clojure inherit some sane thinking found in java. The taking of the good parts of Java is pretty cool. But ultimately. It’s the REPL. Clojure’s REPL is what get’s the people coming back.

Bart Kleijngeld19:04:21

@U0K064KQV You know, the curiosity is there actually. I feel it's mostly fear of getting into something obscure. Also because there might be less people available for contributing to the project.

Bart Kleijngeld19:04:28

@U036UJBDM5G Yes I've already shown some fragments of talks by Rich Hickey where he talks about spec and the RDF inspiration. And it's good to stretch the REPL's advantage. I think that's a selling point I might be able to capitalize on.

Bart Kleijngeld19:04:56

Tips on how to make my colleagues and manager feel safe regarding choosing a language that's relatively obscure in terms of how many people are available for hire, and that isn't statically typed, are very welcome 🙂

Patrick Brown19:04:40

Well, there is core.typed, but I don’t have any experience there.

👍 1

For the manager, I've found what work best is twofold : 1. Any programmer worth their salt should be able to ramp up to it in 2 months and be productive and able to contribute after that. 2. It's niche, but that means it actually attracts people. It's a selling point for the people who want to work in it. So it can be a recruiting advantage.

🙌 3
Bart Kleijngeld07:05:48

I like that second point. I believe Paul Graham has called that "Python's paradox". (The irony with regards to Python's evolution can probably be left unspoken 😉). Good reminder

Patrick Brown18:04:15

I’m a touch macro dumb. I’m trying to call the defspec macro from with the *ns * I’m currently calling it from. Predictably it doesn’t like expanding the ns var, but it uses unqualified symbols in the macro body, so hmmm. So macro-dumb in fact I can’t even ask this question right. Macroexpand is too much noise for the open, but I’ll paste it in the thread if anyone replies.


Without macroexpand - how exactly are you using the macro?

Patrick Brown18:04:24

Cool! Thanks for jumping in. This is cribbed straight from the docs…

(defspec *ns*
  (:link [occupants :is-many :Occupant])
  [mailbox :is-a :Mailbox]
  [color :is-a :Color :required])
That’s what I want to call.


Well, not that straight given that the docs use House instead of *ns*. :) But what exactly are you trying to achieve? Why would you want a spec a.b.c in a namespace a.b.c? Or does the spec-tacular library simply ignore the namespaces and House in a.b.c would conflict with House in x.y.z?

Patrick Brown18:04:54

I want to generate a spec that matches the namespace that has my clojure.spec in it, then generate the actual spec and spit it in an .edn file which matches the structure of my resources/schemas/* So in ‘com.example.person’ I invoke the function that then generates a raw datomic schema for :com.example.person entities in the namespace structured folder /resources/schemas/com/example/person.edn This matches /resources/data/com/example/person.edn Which are the entities I want to migrate to the database.


I see. Well, to the extent needed to answer to initial question anyway. You'll have to write your own macro for that:

(defmacro def-ns-spec [& args]
  (concat (list `defspec (ns-name *ns*)) args))
or something like that.


You'd use it without the first argument, because it would be automatic.

Patrick Brown19:04:44

That is so simple. Great solution. Appreciated!!!

👍 1