Seamless C++ interop in a native Clojure dialect

Written by an AI pipeline from the sources listed below and checked automatically for tone and accuracy. It may still contain mistakes, so check the sources for anything important.
A recent demo showed a Clojure-style REPL calling Boost’s file_size directly, returning either the size in bytes or a Boost exception message. The snippet runs without any JNI bridge, manual marshalling, or generated wrapper code. That is exactly what jank promises: a native Clojure dialect that talks to C++ as naturally as Clojure talks to Java.
In the example below the namespace declares (:include "boost/filesystem.hpp") and then uses file-size just like a regular Clojure function. The cpp/cast helper converts a Clojure string to std::string, and a catch clause can handle a C++ exception type directly. The result is a map that looks familiar to any Clojure programmer, but the heavy lifting happens in compiled C++.
(ns my.app.filesystem
(:include "boost/filesystem.hpp")
(:refer-global :rename {boost.filesystem.file_size file-size}))
(defn file-info [file-path]
(try
(let [bytes (file-size (cpp/cast std.string file-path))]
{:path file-path :size bytes})
(catch boost.filesystem.filesystem_error e
{:path file-path :error (.what e)})))
Running (file-info "/etc/passwd") yields {:path "/etc/passwd", :size 4025} while a permission error produces a map with the exception message. No Java interop, no foreign function interface, just straight C++ inside a Clojure REPL.
How jank blends Clojure and C++
jank sits on top of C++ instead of the JVM. The language retains Clojure’s immutable data structures, persistent collections, and macro system, but swaps Java interop for direct C++ interop. Because the runtime is built on LLVM, every form is compiled to native code before execution. The result is a single binary that can be AOT-compiled for distribution, yet still offers the interactive feel of a REPL.
The design eliminates the “Java-Clojure bridge” that most Clojure implementations rely on. Instead of generating Java classes or using reflection, jank’s reader understands (:include ...) directives and maps C++ symbols into the Clojure namespace. Templates, virtual functions, overload resolution, and RAII work out of the box. The source notes that “templates, virtual functions, exceptions, overload resolution, and RAII all just work in jank. No boilerplate necessary.”
Zero-boilerplate interop with C++ features
Traditional C++ interop layers require explicit binding code, often generated by tools such as SWIG or manually written wrappers. jank removes that step. Including a header file is enough to expose the symbols. The (:refer-global :rename …) clause lets you bring a C++ function into the Clojure namespace under a Clojure-friendly name, as shown with file-size.
Because jank uses the C++ type system directly, you can call overloaded functions, instantiate templates, and catch C++ exceptions without any extra glue. The cpp/cast helper demonstrates how a Clojure value is turned into a C++ type in a single expression. No separate marshaling layer means fewer runtime errors and better performance, especially when dealing with RAII-managed resources like file handles or OpenGL contexts.
REPL-driven development with a LLVM JIT
jank’s REPL is powered by a Clang-based JIT compiler. Each expression you type is compiled to LLVM IR, optimized, and executed immediately. This gives the same rapid feedback loop that Clojure developers expect, but the code runs at native speed. The source describes the REPL as “interactive REPL-driven development powered by a Clang-based C++ JIT compiler.”
The JIT also respects C++’s compilation model. You can define new functions, include additional headers, and even link against freshly built native libraries without restarting the session. This is particularly handy for game development, where the example on the site shows a full ImGui/GLFW loop written entirely in jank, with cpp/glfwInit and cpp/ImGui.NewFrame called from the REPL. The ability to iterate on rendering code in real time is a direct benefit of the JIT.
Building native dependencies the Cargo way
Managing C++ libraries is notoriously painful in the JVM world. jank adopts a Cargo-inspired workflow: dependencies are declared in the project file, and the build system fetches or builds them automatically. The example defproject shows a typical Leiningen-style project that lists C++ libraries such as imgui-glfw-sys and gl-sys with version strings that look like Cargo packages.
When you add a new dependency, you edit a single line in the project map and let jank’s native build system resolve the include paths and link flags. The build can locate installed system libraries or compile them from source, mirroring Cargo’s “build-or-use-system” approach. This reduces the friction of pulling in a library like Boost, OpenGL, or a custom C++ engine.
The takeaway
jank removes the boilerplate that normally separates Clojure from C++. By treating C++ headers as first-class imports, it lets you call templates, catch exceptions, and manage resources directly from a REPL. Use the (:include …) and (:refer-global …) forms to pull C++ symbols into your namespace, and let the LLVM JIT give you instant feedback while you stay in native code. This combination makes it practical to write high-performance, REPL-driven applications without the overhead of a Java bridge.