About
"Clojang" is a set of libraries and tools (including the library
clojang
-proper) that are dedicated to Clojure-BEAM
interop, where BEAM languages include all those of the Erlang
ecosystem: Erlang, LFE, Elixir, Joxa, Reia, Luerl, Erlog, etc.
Clojang supports production deployments of distributed, fault-tolerant, soft real-time BEAM/JVM applications with appropriate restart and fail-over strategies and hot code-loading.
In particular, the aim of Clojang is to support production deployments of distributed, fault-tolerant, soft real-time BEAM/JVM applications, capable of running JVM code in supervision trees with appropriate restart and fail-over strategies, hot code-loading (live system updates with no downtime), and the like.
From the developer perspective, Clojang wants to make OTP-based communications between BEAM languages and the JVM as Clojure-idiomatic as possible and as natural to BEAM programmers as can reasonably be provided.
For an overview of the three primary ways in which one may develop JVM-BEAM interoperable applications, be sure to read the API comparison docs. To see how LFE and Clojure applications can interoperate, you'll want to read the "Talking to Servers" tutorial.
Sample Code
Here's a Clojure OTP server written using Clojang:
(defn ping-pong
[]
(let [init-state 0]
(loop [png-count init-state]
(match (receive)
[:ping caller]
(do (! caller :pong)
(recur (inc png-count)))
[:get-ping-count caller]
(do (! caller png-count)
(recur png-count))
[:stop caller]
(do (! caller :stopping)
:stopped)))))
And here's LFE talking to Clojure:
(clojang-lfe@host)> (! #(default clojang@host) `#(ping ,(self)))
#(ping <0.34.0>)
(clojang-lfe@host)> (! #(default clojang@host) `#(ping ,(self)))
#(ping <0.34.0>)
(clojang-lfe@host)> (! #(default clojang@host) `#(ping ,(self)))
#(ping <0.34.0>)
(clojang-lfe@host)> (c:flush)
Shell got pong
Shell got pong
Shell got pong
ok
(clojang-lfe@host)> (! #(default clojang@host) `#(get-ping-count ,(self)))
#(get-count <0.34.0>)
(clojang-lfe@host)> (c:flush)
Shell got 3
ok
Here's part of an LFE OTP gen_server
:
(defun handle_call
(('ping _caller state-data)
`#(reply pong ,(+ 1 state-data)))
(('ping-count _caller state-data)
`#(reply ,state-data ,state-data))
(('stop _caller state-data)
`#(stop shutdown ok ,state-data))
((_message _caller state-data)
`#(reply ,(unknown-command) ,state-data)))
And here's Clojure talking to LFE:
clojang.dev=> (rpc/! :clojang-lfe :ping-pong :ping)
:ok
clojang.dev=> (rpc/! :clojang-lfe :ping-pong :ping)
:ok
clojang.dev=> (rpc/! :clojang-lfe :ping-pong :ping)
:ok
clojang.dev=> (rpc/receive :clojang-lfe)
:pong
clojang.dev=> (rpc/receive :clojang-lfe)
:pong
clojang.dev=> (rpc/receive :clojang-lfe)
:pong
clojang.dev=> (rpc/! :clojang-lfe :ping-pong :get-ping-count)
:ok
clojang.dev=> (rpc/receive :clojang-lfe)
3