Why Kotlin Multiplatform¶
Plain tuProlog was a Java library: anything built on it had to run on a JVM, and anything that wanted to talk to it from outside the JVM needed some kind of bridge. That constraint sat uneasily with where the projects built on tuProlog were actually headed — coordination models for mobile and web agents, logic solvers meant to run on IoT/edge devices, browser-hosted reasoners — all of which wanted a logic engine that did not assume a JVM was present. Rewriting from scratch (see Project History) was the opportunity to fix that at the foundation instead of bridging around it.
Why Kotlin specifically¶
Kotlin was chosen over, say, keeping the codebase in Java or moving it to a JVM-only alternative, for a fairly small set of concrete reasons:
- One source, several platforms. Kotlin Multiplatform lets the same
commonMainsource set compile to genuinely different targets (a JVM library, a JavaScript library) without hand-porting the logic twice. For a project whose whole point is a shared, well-testedcore/unify/theory/solvestack (see Design Philosophy), duplicating that stack per platform was never an option worth considering — a bug fixed once incommonMainis fixed everywhere. - Interop in both directions. A Kotlin/JVM artifact is usable from plain Java with no special ceremony,
and a Kotlin/JS artifact is usable from plain JavaScript/TypeScript in the same way. That matters directly
for tuProlog's long-standing goal of bidirectional OOP interoperability (see
:oop-lib): the host language's objects need to be reachable from Prolog and vice versa, on whichever platform the host happens to be. - Practical, modern tooling, without requiring the project to abandon the JVM ecosystem (Gradle, Maven Central, the existing tuProlog user base) it was already part of.
What this actually buys, and its cost¶
The upside is real: a single :core module change is validated against every platform target in one build,
and users get to pick the deployment that fits them — a JVM library, an npm package, a self-contained
desktop GUI — from the same codebase, with dependency management (Gradle module graph, see Module
map) doing the work of keeping platform-specific artifacts consistent with each
other.
The cost is that commonMain code can only rely on the Kotlin common standard library, not on
java.util.* or platform-specific browser APIs. Anything that genuinely needs a platform capability has to
be written against a Kotlin expect/actual declaration, with one implementation per target — which is
exactly why the module graph keeps a hard line between "common" modules and modules that are frankly
platform-specific by necessity.
The current targets, precisely¶
It is easy to over-state Kotlin Multiplatform's reach in the abstract, so it is worth being precise about
what 2P-Kt actually builds for today, per the project's own Gradle configuration: JVM and JavaScript.
Most modules opt into both automatically; a handful of modules are deliberately JVM-only — :ide,
:ide-plp, and :examples — because they depend on JavaFX for their GUI, which has no JS or other-platform
equivalent. Everything else in the ecosystem, including :core, :unify, :theory, and the :solve-*
family, is common code compiled for both targets.
Earlier design notes for this project (circa 2021) described Android and Kotlin/Native support as open
questions, and singled out :oop-lib as JVM-only because Kotlin's reflection API — which OOP interop
depends on to inspect host objects at runtime — was not available on other platforms at the time. Neither
claim reflects the current codebase: Android and Native are not targeted, and :oop-lib has since gained a
real JavaScript implementation (TypeUtilsJs.kt) alongside its JVM one, sitting behind the same common
API. This is a reasonable trajectory for a multiplatform project to take — platform reach tends to expand
where it is actually needed, rather than being front-loaded speculatively.