\documentclass[11pt,twocolumn]{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{amsmath,amssymb,amsthm}
\usepackage{mathtools}
\usepackage{stmaryrd}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{graphicx}
\usepackage{booktabs}
\usepackage{multirow}
\usepackage{hyperref}
\usepackage{cleveref}
\usepackage{enumitem}
\usepackage{tabularx}
\usepackage{float}
\usepackage{microtype}
\usepackage[margin=0.85in]{geometry}
\usepackage{natbib}
\usepackage{url}
\usepackage{tikz}
\usetikzlibrary{arrows.meta,positioning,calc,shapes.geometric}

% JAPL language definition for listings
\lstdefinelanguage{japl}{
  keywords={fn, let, match, with, type, if, then, else, use, test, assert, import, module, trait, impl, opaque, forall, property, bench, loop, while, do, continue, own, ref, foreign, unsafe, deriving, signature},
  keywordstyle=\bfseries\color{blue!70!black},
  ndkeywords={Int, Float, String, Bool, Unit, Never, Option, Result, Ok, Err, Some, None, True, False, List, Map, Bytes, Pid, Process, Io, Net, State, Fail, Async, Pure},
  ndkeywordstyle=\bfseries\color{purple!70!black},
  sensitive=true,
  comment=[l]{--},
  commentstyle=\itshape\color{gray},
  string=[b]",
  stringstyle=\color{red!70!black},
  literate={->}{$\rightarrow$}{2} {|>}{$\triangleright$}{2} {>>}{$\ggg$}{2} {<>}{$\diamond$}{2},
  basicstyle=\ttfamily\scriptsize,
  breaklines=true,
  showstringspaces=false,
  tabsize=2,
  frame=single,
  framerule=0.4pt,
  rulecolor=\color{gray!50},
  xleftmargin=2mm,
  xrightmargin=1mm,
}

\lstdefinelanguage{shell}{
  basicstyle=\ttfamily\scriptsize,
  breaklines=true,
  showstringspaces=false,
  frame=single,
  framerule=0.4pt,
  rulecolor=\color{gray!50},
  xleftmargin=2mm,
  xrightmargin=1mm,
  keywordstyle=\bfseries\color{green!40!black},
  keywords={\$},
}

\lstset{language=japl}

\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{proposition}[theorem]{Proposition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{remark}{Remark}[section]

\newcommand{\japl}{\textsc{Japl}}
\newcommand{\BigO}{\mathcal{O}}

\title{\textbf{Runtime Simplicity Matters as Much as Type Power:} \\
\large Predictable Execution, Practical Tooling, and the Operational Philosophy of \japl{}}

\author{
  JAPL Language Design Group \\
  \texttt{matthew@yonedaai.com}
}

\date{March 2026}

\begin{document}

\maketitle

% ============================================================
% ABSTRACT
% ============================================================
\begin{abstract}
Programming language research has historically privileged type system expressiveness over operational concerns such as compilation speed, deployment simplicity, tooling quality, and runtime predictability.
This paper argues that these operational properties are equally important to the long-term success of a language, and that neglecting them produces languages that are \emph{elegant but operationally miserable}---powerful in theory but painful in practice.
We present the design philosophy of \japl{}, a strict, typed, effect-aware functional language whose seventh core principle is \emph{Runtime Simplicity Matters as Much as Type Power}.
We formalize a \emph{type power budget} that constrains type system complexity to features yielding proportionate safety gains, describe a hybrid GC/ownership memory model that provides Erlang-like ease for ordinary values and Rust-like precision for external resources, and detail a compilation model optimized for fast incremental builds and static binary output.
We demonstrate how effect types enable aggressive dead code elimination without sacrificing modularity, how built-in tooling (formatter, test runner, profiler, package manager) reduces friction comparable to Go's unified toolchain, and how cross-compilation and single-binary deployment eliminate entire categories of operational failure.
A comparative case study of building, testing, and deploying a production service in \japl{}, Go, Rust, Haskell, and Erlang quantifies the operational advantages of treating runtime simplicity as a first-class design concern.
Our central thesis is that the design space of programming languages admits a Pareto frontier where substantial type safety and operational simplicity coexist---and that reaching this frontier requires deliberate, principled trade-offs rather than maximal expressiveness.
\end{abstract}

% ============================================================
% 1. INTRODUCTION
% ============================================================
\section{Introduction}
\label{sec:introduction}

The history of programming language design reveals a persistent tension.
On one side stand languages with powerful, expressive type systems---Haskell~\citep{marlow2010haskell}, Scala~\citep{odersky2004scala}, Rust~\citep{matsakis2014rust}---that offer strong compile-time guarantees but impose significant operational costs: slow compilation, complex deployment, steep learning curves, and opaque runtime behavior.
On the other side stand languages like Go~\citep{pike2012go} and Lua~\citep{ierusalimschy2006lua} that prioritize simplicity, fast builds, and straightforward deployment, but sacrifice type-level expressiveness that could prevent entire classes of bugs.

This tension is not merely aesthetic.
It has direct consequences for software reliability, developer productivity, and organizational adoption.
A language with a perfect type system that takes thirty minutes to compile a medium-sized project \emph{will lose to} a language with adequate types that compiles in two seconds---not because practitioners are lazy, but because fast feedback loops are a prerequisite for iterative development, and iterative development is how working software gets built.

\subsection{The Usability Crisis}

We identify a \emph{usability crisis} in modern programming language design, characterized by several failure modes:

\begin{enumerate}[leftmargin=*]
\item \textbf{The compilation wall.} Rust projects routinely report clean-build times exceeding ten minutes for moderate codebases~\citep{rust-compile-survey-2023}. Haskell's GHC is notorious for slow Template Haskell compilation and long linking phases. These delays compound: every failed CI run, every developer context switch, every ``let me check if this compiles'' represents lost time that accumulates to hours per week per developer.

\item \textbf{The deployment labyrinth.} Deploying a Haskell application requires navigating a maze of dynamically linked libraries, Cabal/Stack version conflicts, and platform-specific GHC builds~\citep{snoyman2017haskell-deployment}. Erlang applications require a BEAM VM installation on every target machine. Even Rust, which produces static binaries, requires careful management of C library dependencies on Linux.

\item \textbf{The tooling desert.} Languages with rich type systems often have fragmented tooling: multiple build systems (Haskell's Cabal vs. Stack vs. Nix), inconsistent formatting conventions, third-party test frameworks with incompatible interfaces, and language servers that lag behind compiler features.

\item \textbf{The debugging opacity.} Lazy evaluation in Haskell produces stack traces that bear no relation to the source code's control flow~\citep{allwood2009stack-traces}. Rust's deeply nested generic types produce error messages measured in kilobytes. Complex type-level programming creates abstractions that debuggers cannot inspect.
\end{enumerate}

\subsection{Go's Social Lesson}

Go's extraordinary adoption---despite a type system that professional language designers consider primitive~\citep{griesemer2020generics}---demonstrates that operational excellence creates its own gravitational pull.
Go compiles a 100,000-line project in under two seconds.
\texttt{go build} produces a single static binary.
\texttt{gofmt} ended all formatting debates.
\texttt{go test} requires zero configuration.
Cross-compilation is a single environment variable.

Pike~\citep{pike2012go} was explicit about this: Go was designed for the \emph{working programmer} building \emph{production systems}, not for the language researcher exploring the type-theoretic frontier.
The result is a language that is mundane to write in and delightful to deploy---and that combination proved to be exactly what a large segment of the industry needed.

\subsection{The Elegant-but-Miserable Failure Mode}

We coin the term \emph{elegant but operationally miserable} (EBOM) for languages that score highly on type-theoretic metrics but poorly on operational ones.
The EBOM failure mode is characterized by:
\begin{itemize}[leftmargin=*]
\item Conference papers praising the type system while production users struggle with deployment
\item A small, devoted community that views operational complaints as skill issues
\item A persistent gap between ``Hello World'' tutorials and production readiness
\item Academic adoption without proportionate industrial adoption
\end{itemize}

Our thesis is that this failure mode is avoidable.
The design space of programming languages admits a Pareto frontier where substantial type safety and operational simplicity coexist.
\japl{} is an attempt to reach that frontier through deliberate, principled trade-offs.

\subsection{Contributions}

This paper makes the following contributions:
\begin{enumerate}[leftmargin=*]
\item A formal \emph{type power budget} framework (\Cref{sec:type-power-budget}) that evaluates type system features by their safety-per-complexity ratio, providing principled criteria for feature inclusion/exclusion.
\item A detailed description of \japl{}'s hybrid GC/ownership memory model (\Cref{sec:memory-model}) that achieves GC ease for common cases and ownership precision for resources.
\item An analysis of \japl{}'s compilation model (\Cref{sec:compilation}) showing how effect types enable optimization opportunities unavailable to languages with unrestricted side effects.
\item A comparative case study (\Cref{sec:case-study}) quantifying the operational differences between \japl{}, Go, Rust, Haskell, and Erlang for a representative production workload.
\item A design rationale for treating tooling as a language feature (\Cref{sec:tooling}), not an afterthought.
\end{enumerate}

% ============================================================
% 2. BACKGROUND AND RELATED WORK
% ============================================================
\section{Background and Related Work}
\label{sec:background}

\subsection{Go's Design Philosophy}

Go~\citep{pike2012go,donovan2015go} was designed at Google by Rob Pike, Ken Thompson, and Robert Griesemer with an explicit focus on large-scale software engineering.
Its design priorities---fast compilation, minimal language surface, built-in concurrency, static binaries, and canonical formatting---were driven by the pain of working with C++ at Google scale.

Pike's influential talk ``Simplicity is Complicated''~\citep{pike2015simplicity} articulated a core insight: simplicity in a programming language is itself a feature that requires significant design effort.
Go's designers made controversial choices---no generics (until Go 1.18), no algebraic data types, no pattern matching, no exceptions---because each feature would add complexity to compilation, tooling, and comprehension.

The key lessons from Go's success that inform \japl{}'s design:
\begin{enumerate}[leftmargin=*]
\item \textbf{Compilation speed is a feature.} Go's compiler was designed from the start to be fast, with dependency analysis that avoids recompiling unchanged packages.
\item \textbf{Canonical tooling eliminates social friction.} \texttt{gofmt} ended formatting wars; \texttt{go test} standardized testing; \texttt{go vet} codified best practices.
\item \textbf{Single-binary deployment is transformative.} Eliminating shared library dependencies removes an entire failure mode category from production systems.
\item \textbf{Cross-compilation should be trivial.} Go's \texttt{GOOS} and \texttt{GOARCH} environment variables make cross-compilation a non-event.
\end{enumerate}

\subsection{Rust's Compile Time Debate}

Rust~\citep{matsakis2014rust,klabnik2019rust} provides powerful type-level guarantees---ownership, borrowing, lifetimes, trait-based generics---at the cost of compilation speed.
The Rust community has engaged in extensive discussion about compile times, with the \texttt{cargo build} experience being a persistent pain point~\citep{rust-compile-survey-2023}.

Several factors contribute to Rust's compilation cost:
\begin{itemize}[leftmargin=*]
\item \textbf{Monomorphization:} Generic functions are compiled separately for each concrete type, producing better code at the cost of more compilation work.
\item \textbf{Borrow checking:} The ownership and lifetime analysis is a whole-function analysis that does not parallelize trivially.
\item \textbf{LLVM backend:} Rust's use of LLVM provides excellent code generation but LLVM itself is not fast.
\item \textbf{Procedural macros:} Rust's macro system requires compiling and executing Rust code during compilation.
\end{itemize}

Matsakis and others have investigated incremental compilation~\citep{matsakis2016incremental} and parallel codegen as mitigations, but the fundamental trade-off remains: Rust's type system \emph{requires} analysis that is inherently more expensive than Go's simpler type checking.

\japl{} learns from Rust that ownership and linear types are valuable for resource management, but avoids making ownership the \emph{universal} memory management strategy, thereby reducing the scope of expensive lifetime analysis.

\subsection{Haskell's Deployment Challenges}

Haskell~\citep{marlow2010haskell,jones2003haskell} represents the state of the art in type system expressiveness for a general-purpose language, with type classes, higher-kinded types, GADTs, type families, and dependent types (via extensions).
However, deploying Haskell applications in production remains difficult:

\begin{itemize}[leftmargin=*]
\item \textbf{Dynamic linking by default:} GHC-compiled binaries depend on shared libraries that must be present on the target system.
\item \textbf{Build system fragmentation:} The Haskell ecosystem has cycled through Cabal, Stack, and Nix-based builds without convergence.
\item \textbf{Runtime unpredictability:} Lazy evaluation can cause space leaks that are difficult to diagnose~\citep{mitchell2013leaking}.
\item \textbf{Cross-compilation:} Cross-compiling Haskell is possible but requires significant setup compared to Go or Rust.
\end{itemize}

Snoyman~\citep{snoyman2017haskell-deployment} documented these challenges in detail, noting that Haskell's deployment story is the primary barrier to adoption in organizations that have already accepted the language's type system.

\subsection{OCaml's Pragmatism}

OCaml~\citep{leroy2014ocaml} occupies an interesting middle ground: a type system with algebraic data types, parametric polymorphism, and a powerful module system, combined with a simple compilation model that produces fast native code.
OCaml compiles quickly, produces reasonable executables, and has a straightforward deployment model.

However, OCaml's ecosystem has historically suffered from tooling gaps: no canonical formatter (until \texttt{ocamlformat}), fragmented build systems (ocamlbuild, jbuilder/dune), and a package ecosystem smaller than Haskell's or Rust's.
Recent efforts---opam 2.0, dune, the OCaml Language Server Protocol implementation---have improved the situation significantly.

\subsection{Gleam's Simplicity-First Approach}

Gleam~\citep{gleam2023} is a typed language that targets the BEAM virtual machine, bringing algebraic data types and exhaustive pattern matching to the Erlang ecosystem.
Gleam's design philosophy explicitly prioritizes simplicity: no macros, no operator overloading, no implicit behavior, a single canonical formatter.

Gleam demonstrates that meaningful type safety is achievable without the full weight of Haskell's type system.
Its limitation---targeting only the BEAM---means it inherits BEAM's deployment model (requiring the Erlang runtime).

\subsection{Zig's Comptime}

Zig~\citep{kelley2020zig} introduces \texttt{comptime}, a mechanism for compile-time code execution that replaces both generics and macros with a single, unified concept.
Zig's approach is notable for its transparency: the same language is used at compile time and run time, making the compilation model easier to understand and debug.

Zig also demonstrates that a language can achieve cross-compilation excellence by designing for it from the start, using a self-hosted compiler that bundles its own C library implementations.

\subsection{Erlang's Runtime Philosophy}

Erlang~\citep{armstrong2003erlang,armstrong2007erlang} and its runtime (the BEAM~\citep{happi2023beam}) provide the gold standard for runtime observability:
\begin{itemize}[leftmargin=*]
\item Hot code loading: deploying new code without stopping the system
\item Process inspection: examining any process's state, mailbox, and call stack at runtime
\item Tracing: enabling per-function tracing without recompilation
\item Distribution: transparent cross-node communication
\end{itemize}

The BEAM's reduction-based scheduler provides fair, preemptive scheduling of lightweight processes, with each process independently garbage-collected.
This model---per-process heaps, no shared mutable state, preemptive scheduling---directly inspires \japl{}'s runtime design.

% ============================================================
% 3. FORMAL FRAMEWORK
% ============================================================
\section{Formal Framework}
\label{sec:formal-framework}

We formalize the interaction between type system complexity and operational quality, providing a principled basis for the design trade-offs in \japl{}.

\subsection{Compiler Architecture for Fast Compilation}

Let $P$ denote a program consisting of modules $M_1, \ldots, M_n$ with dependency graph $G = (V, E)$ where $V = \{M_i\}$ and $(M_i, M_j) \in E$ iff $M_i$ depends on $M_j$.

\begin{definition}[Compilation Cost Model]
The total compilation time $T(P)$ for a program $P$ with parallelism $k$ is:
\[
T(P) = T_{\text{parse}} + T_{\text{type}} + T_{\text{opt}} + T_{\text{codegen}} + T_{\text{link}}
\]
where each phase has cost determined by the critical path through $G$ given $k$ workers:
\[
T_{\text{phase}}(P, k) = \frac{W_{\text{phase}}(P)}{k} + D_{\text{phase}}(G)
\]
Here $W_{\text{phase}}$ is the total work and $D_{\text{phase}}$ is the span (longest dependent chain) for that phase.
\end{definition}

\begin{proposition}[Type Checking Dominates]
For languages with \emph{unrestricted type-level features} (HKTs, GADTs, type families, dependent types), type checking dominates compilation:
\[
\lim_{|P| \to \infty} \frac{T_{\text{type}}(P)}{T(P)} \to 1
\]
This limit applies specifically to languages that permit open-ended type-level computation; languages like \japl{} that bound their type systems to decidable fragments avoid this asymptotic behavior.
In particular, Hindley-Milner inference is $\BigO(n)$ for practical inputs~\citep{mcadam1998complexity} but extensions like type families introduce decision procedures that are NP-complete or undecidable in the general case~\citep{sulzmann2007type-families}.
\end{proposition}

\subsection{Incremental Compilation}

\begin{definition}[Incremental Compilation Efficiency]
Given a change $\delta$ to module $M_i$, the incremental recompilation set is:
\[
\text{Recomp}(\delta) = \{M_i\} \cup \{M_j : M_j \text{ transitively depends on } M_i \text{ and } \text{iface}(M_i) \text{ changed}\}
\]
The incremental efficiency ratio is:
\[
\eta(\delta) = 1 - \frac{|\text{Recomp}(\delta)|}{|V|}
\]
\end{definition}

A language design that stabilizes module interfaces---for example, by separating interface declarations from implementations, as pioneered by Modula-2~\citep{wirth1982modula2} and Ada~\citep{ichbiah1979ada}---maximizes $\eta$ because most changes are implementation-only and do not propagate.

\japl{}'s module system requires explicit signatures at module boundaries.
When a module's implementation changes but its signature does not, downstream modules need not be recompiled.
Effect annotations in signatures provide additional stability: if a function's effects do not change, downstream code that depends on those effects remains valid.

\subsection{Decidability vs. Expressiveness}

\begin{theorem}[Expressiveness--Decidability Trade-off]
\label{thm:expressiveness}
Let $\mathcal{L}$ be a type system with decision procedure $D_\mathcal{L}$ for type checking.
The following hierarchy of type system features has increasing worst-case complexity for $D_\mathcal{L}$:

\begin{enumerate}
\item Simple types (Hindley-Milner): decidable, $\BigO(n)$ practical
\item Bounded quantification (System $F_{<:}$): decidable, potentially exponential~\citep{pierce2002types}
\item Type classes with functional dependencies: decidable with restrictions, undecidable in general~\citep{sulzmann2007type-families}
\item GADTs: type checking decidable, type inference undecidable~\citep{jones2006gadts}
\item Dependent types: type checking is undecidable in general (reduces to the halting problem)
\end{enumerate}
\end{theorem}

\japl{} draws the line between items 2 and 3: it includes algebraic data types, parametric polymorphism, traits (type classes without functional dependencies), row polymorphism, and effect types, while excluding GADTs, type families, and dependent types.
This boundary ensures that type checking remains decidable and practically fast.

\subsection{Effect Types and Optimization}

Effect annotations create optimization opportunities unavailable to languages with unrestricted side effects.

\begin{proposition}[Effect-Based Dead Code Elimination]
Let $f$ be a function with effect signature $\epsilon_f$ and let $e$ be an expression that calls $f$.
If $\epsilon_f = \text{Pure}$ and the result of $e$ is unused, then $e$ can be eliminated.
More generally, if $\epsilon_f$ does not include $\text{Io}$ or $\text{Process}$, and the result is unused, elimination is safe if the remaining effects ($\text{State}$, $\text{Fail}$) are handled locally.
\end{proposition}

This is strictly stronger than the optimizations available to Go or OCaml, where any function call might perform I/O, and the compiler must conservatively retain all calls.

% ============================================================
% 4. JAPL'S RUNTIME PHILOSOPHY
% ============================================================
\section{\japl{}'s Runtime Philosophy}
\label{sec:runtime-philosophy}

\japl{}'s seventh principle---\emph{Runtime Simplicity Matters as Much as Type Power}---is not merely a preference but a design constraint that shapes every aspect of the language and its implementation.
We enumerate the concrete commitments this principle entails.

\subsection{Single Fast Compiler}

\japl{} ships a single compiler, \texttt{japlc}, that is the canonical and only implementation.
There is no alternative compiler, no compiler plugin ecosystem that fragments the language, and no compiler flags that change the semantics of valid programs.

The compiler targets two backends:
\begin{itemize}[leftmargin=*]
\item \textbf{Cranelift}~\citep{cranelift2020}: For fast debug builds. Cranelift is designed for fast code generation with reasonable code quality, making it ideal for the edit-compile-test loop.
\item \textbf{LLVM}~\citep{lattner2004llvm}: For optimized release builds. LLVM provides state-of-the-art code generation at the cost of slower compilation.
\end{itemize}

The default (\texttt{japl build}) uses Cranelift; \texttt{japl build --release} uses LLVM.
This dual-backend strategy provides Go-like compilation speed for development and Rust-like code quality for production.

\subsection{Single Standard Formatter}

\begin{lstlisting}[language=shell]
$ japl fmt              # format current project
$ japl fmt --check      # check without modifying
$ japl fmt src/main.japl # format single file
\end{lstlisting}

\texttt{japl fmt} is an opinionated formatter with no configuration options, following Go's \texttt{gofmt} philosophy.
There is one canonical style.
Formatting debates are impossible because the tool's output is the definition of correct formatting.

This decision is informed by Go's experience: \texttt{gofmt} is widely regarded as one of Go's most impactful features, not because of any particular formatting choice, but because it eliminated an entire category of unproductive discussion~\citep{pike2012go}.

\subsection{Dead-Simple Build Tool}

\japl{}'s build tool is integrated into the compiler.
There is no separate build system, no Makefile, no configuration file for basic projects:

\begin{lstlisting}[language=shell]
$ japl build            # compile the project
$ japl build --release  # optimized build via LLVM
$ japl run              # compile and execute
$ japl run --profile    # compile and execute with profiling
\end{lstlisting}

Project configuration, when needed, lives in a single \texttt{japl.toml} file:

\begin{lstlisting}[language=japl,basicstyle=\ttfamily\scriptsize]
-- japl.toml
name = "my-service"
version = "1.2.0"

[deps]
http = "0.5"
json = "1.0"
postgres = "0.3"
\end{lstlisting}

\subsection{Small, High-Quality Standard Library}

\japl{}'s standard library follows Go's approach of including enough to be productive without external dependencies for common tasks:

\begin{itemize}[leftmargin=*]
\item \texttt{Std.Http} -- HTTP client and server
\item \texttt{Std.Json} -- JSON encoding/decoding
\item \texttt{Std.Crypto} -- Cryptographic primitives
\item \texttt{Std.Fs} -- File system operations
\item \texttt{Std.Net} -- TCP/UDP networking
\item \texttt{Std.Test} -- Testing framework
\item \texttt{Std.Time} -- Time and duration
\item \texttt{Std.Log} -- Structured logging
\item \texttt{Std.Trace} -- Distributed tracing
\end{itemize}

The standard library is intentionally \emph{small}: it includes only functionality that most server-side applications need, is difficult to get right independently, or benefits from tight integration with the runtime (e.g., process-aware logging).

\subsection{Built-in Test Runner}

Tests are a language construct, not a library convention:

\begin{lstlisting}
test "user creation validates email" {
  let result = create_user("bad-email")
  assert result == Err(InvalidEmail("bad-email"))
}

test "order total includes tax" {
  let order = make_order([item(10.0), item(20.0)])
  let total = calculate_total(order, tax_rate = 0.1)
  assert total == 33.0
}

property "reversing twice is identity" {
  forall (xs: List[Int]) ->
    List.reverse(List.reverse(xs)) == xs
}
\end{lstlisting}

\begin{lstlisting}[language=shell]
$ japl test             # run all tests
$ japl test --filter user  # run matching tests
$ japl test --parallel 8   # parallel test execution
$ japl test --coverage     # with coverage report
\end{lstlisting}

Tests are discovered by the compiler, not by file naming conventions or annotation processing.
The compiler knows about tests, which enables test-aware optimizations (e.g., skipping code generation for non-test code when running tests).

\subsection{Cross-Compilation}

\begin{lstlisting}[language=shell]
$ japl build --target linux-amd64
$ japl build --target linux-arm64
$ japl build --target darwin-arm64
$ japl build --target darwin-amd64
$ japl build --target windows-amd64
$ japl build --target wasm32
\end{lstlisting}

Cross-compilation works out of the box because the compiler bundles everything needed to generate code for all supported targets.
There are no external dependencies, no target-specific SDK installations, and no platform-specific configuration.

\subsection{Static Binaries}

\begin{lstlisting}[language=shell]
$ japl build --static myapp.japl
$ file ./myapp
./myapp: ELF 64-bit LSB executable, statically linked
$ ldd ./myapp
  not a dynamic executable
\end{lstlisting}

Every \japl{} build produces a single static binary with no external dependencies.
The binary includes the \japl{} runtime (scheduler, GC, network stack) and all application code.
This is the \emph{only} deployment artifact.

\subsection{Readable Stack Traces}

When a \japl{} process crashes, the stack trace maps directly to source code:

\begin{lstlisting}[language=shell,basicstyle=\ttfamily\tiny]
Process <0.47.0> crashed: DivisionByZero
  at Math.divide        (src/math.japl:42:15)
  at Order.calculate    (src/order.japl:87:10)
  at Handler.process    (src/handler.japl:23:5)
  at Server.handle_req  (src/server.japl:156:3)

Process mailbox (3 messages pending):
  ProcessOrder({id: "ord-123", ...})
  ProcessOrder({id: "ord-456", ...})
  Shutdown

Supervisor <0.12.0> restarting child "order-handler"
  (restart count: 1/5, strategy: OneForOne)
\end{lstlisting}

Strict evaluation ensures that stack traces reflect the actual execution order.
There are no thunks, no lazy chains, and no deferred evaluation that would make the stack trace misleading.

\subsection{Built-in Profiling and Tracing}

\begin{lstlisting}[language=shell]
$ japl run --profile myapp.japl
# Produces: myapp.prof (native profiling data)

$ japl trace --format chrome myapp.japl
# Produces: myapp.trace (Chrome trace format)

$ japl run --gc-stats myapp.japl
# Prints per-process GC statistics
\end{lstlisting}

Profiling and tracing are built into the runtime, not bolted on via sampling profilers or LD\_PRELOAD tricks.
The runtime knows about processes, mailboxes, supervision trees, and effect handlers, and can provide domain-specific profiling information that generic tools cannot.

% ============================================================
% 5. THE GC + OWNERSHIP HYBRID MEMORY MODEL
% ============================================================
\section{The GC + Ownership Hybrid Memory Model}
\label{sec:memory-model}

\japl{}'s memory model is the key architectural decision that enables both runtime simplicity and resource safety.
Rather than choosing between garbage collection (Go, Haskell, Erlang) and ownership (Rust), \japl{} uses both, each in its natural domain.

\subsection{Design Rationale}

The fundamental observation is that most values in a functional program are \emph{immutable data}---algebraic data types, records, strings, closures, collections---while a smaller but critical set of values are \emph{external resources}---file handles, network sockets, database connections, GPU buffers.

These two categories have radically different management requirements:

\begin{table}[H]
\centering
\scriptsize
\begin{tabularx}{\columnwidth}{lXX}
\toprule
\textbf{Property} & \textbf{Immutable Data} & \textbf{Resources} \\
\midrule
Mutability & Never & Often \\
Sharing & Free (no races) & Dangerous \\
Lifetime & Until unreachable & Until explicitly released \\
Cleanup & Whenever (GC) & Immediately (deterministic) \\
Copying & Cheap (structural sharing) & Often impossible \\
\bottomrule
\end{tabularx}
\caption{Distinct management requirements for data vs. resources.}
\label{tab:data-vs-resources}
\end{table}

Applying GC to resources is wrong: GC provides no deterministic cleanup guarantees, so file handles may remain open and connections may leak.
Applying ownership to immutable data is wasteful: lifetime annotations add cognitive overhead for values that can be safely shared without restriction.

\subsection{The Immutable Heap}

The immutable heap is managed by a generational, per-process garbage collector inspired by the BEAM~\citep{happi2023beam}:

\begin{enumerate}[leftmargin=*]
\item \textbf{Per-process heaps.} Each \japl{} process has its own heap partition. GC in one process does not pause other processes. This is critical for latency-sensitive applications: a process handling an HTTP request is not affected by GC in a process doing batch processing.

\item \textbf{No write barriers.} Because all heap data is immutable, there are no pointer updates to track. This eliminates write barriers, simplifying the GC implementation and improving mutator throughput.

\item \textbf{Generational collection.} Most functional programs exhibit generational behavior: most values are short-lived (intermediate results in a pipeline). A nursery/old-generation split captures this efficiently.

\item \textbf{Instant reclamation on process death.} When a process exits, its entire heap is freed in $\BigO(1)$ time, without tracing. This is especially valuable for request-handling processes with short lifetimes.
\end{enumerate}

\begin{lstlisting}
-- All these values live on the immutable heap
-- and are managed by GC. No annotations needed.
let config = { host = "localhost", port = 8080 }
let items = [1, 2, 3, 4, 5]
let doubled = List.map(items, fn x -> x * 2)
let name = "JAPL"

-- Values can be freely shared across processes
-- because they cannot be mutated
Process.send(worker, ProcessData(config, items))
\end{lstlisting}

\subsection{The Resource Arena}

External resources live in a separate arena managed by linear types and ownership tracking:

\begin{lstlisting}
-- Resource layer: ownership-tracked, must be consumed
fn process_file(path: String)
    -> Result[String, IoError] with Io =
  use file = File.open(path, Read)?
  let contents = File.read_all(file)?
  File.close(file)  -- consumed: forgetting = error
  Ok(contents)

-- Transfer ownership between processes
fn send_to_worker(buf: own Buffer,
                  pid: Pid[WorkerMsg]) -> Unit =
  Process.send(pid, ProcessBuffer(buf))
  -- buf is moved; using it here is a compile error
\end{lstlisting}

The ownership rules for the resource arena are:
\begin{enumerate}
\item Every resource has exactly one owner at any time.
\item Ownership can be transferred (\texttt{own} qualifier) but not duplicated.
\item Read-only borrows (\texttt{ref} qualifier) allow temporary shared access.
\item When the owner goes out of scope without consuming the resource, the compiler reports an error.
\item The compiler rejects programs that use a resource after transfer.
\end{enumerate}

\subsection{Interface Between the GC Heap and the Resource Arena}

A critical design question is how the two memory regions interact.
The rule is strict: \emph{immutable values on the GC heap cannot directly contain owned resources.}
Because the GC heap provides no deterministic finalization guarantee, allowing a GC-managed record to hold an \texttt{own File} would make resource cleanup non-deterministic---precisely the failure mode the ownership layer is designed to prevent.

Instead, resources that must be referenced from immutable data structures are wrapped in \emph{process-local handles}: opaque, copyable identifiers that index into the process's resource arena.
A handle has type \texttt{Handle[R]} for resource type \texttt{R}, and is an ordinary immutable value that can be freely placed in records, lists, or any GC-managed collection.
The actual resource remains in the arena, subject to ownership tracking.

\begin{lstlisting}
-- A Handle[File] is a copyable, GC-managed token.
-- The File itself stays in the resource arena.
let h: Handle[File] = Resource.register(file)
let config = { name = "log", target = h }

-- To use the resource, borrow it via the handle:
Resource.with(config.target, fn (f: ref File) ->
  File.write(f, "entry"))

-- Explicit release through the handle:
Resource.release(config.target)
-- Further borrows via this handle are compile errors.
\end{lstlisting}

The compiler enforces this separation through a \emph{kind distinction}: types of kind \texttt{Resource} (those carrying ownership obligations) are excluded from appearing as fields of types of kind \texttt{Data} (the default kind for GC-managed values).
Any attempt to embed an \texttt{own File} directly inside a record or list is a kind error.
When a programmer needs a collection of resources, \japl{} provides \emph{linear collections} (e.g., \texttt{LinearList[own File]}) that themselves carry ownership obligations and must be consumed explicitly.
These linear collections live in the resource arena, not the GC heap, preserving deterministic cleanup.

This design means that resources are \emph{second-class} with respect to standard collections: an \texttt{own File} cannot be placed in a regular \texttt{List} or \texttt{Map}.
Linear collections exist for the cases where resource aggregation is needed, but the common case---packaging immutable data into standard collections---remains free of ownership annotations.

\subsection{Why This Is the Sweet Spot}

\begin{theorem}[Hybrid Memory Model Correctness]
\label{thm:hybrid-correct}
The \japl{} hybrid memory model satisfies the following properties:
\begin{enumerate}
\item \textbf{Data race freedom:} No data races are possible on immutable heap data (trivially, since data is immutable) or resource arena data (since resources have a single owner).
\item \textbf{Resource safety:} Every allocated resource is eventually freed, and no resource is used after freeing.
\item \textbf{No annotation overhead for common case:} Immutable data (the vast majority of values in a functional program) requires no ownership annotations.
\end{enumerate}
\end{theorem}

\begin{proof}[Proof sketch]
(1) follows from immutability of heap data and single-ownership of arena data.
(2) follows from the linearity constraint: the compiler's type system ensures that every resource is consumed exactly once, either by explicit deallocation or by transfer to another owner.
(3) follows from the fact that GC-managed data requires no programmer-visible lifetime management.

We strengthen claim (2) with a small-step operational semantics sketch.
Define a program state $\sigma = (H, A, e)$ where $H$ is the immutable GC heap, $A$ is the resource arena (a finite map from resource identifiers to resource states $\{\textsc{Live}, \textsc{Freed}\}$), and $e$ is the expression under evaluation.
The key reduction rules for resources are:
\begin{align*}
\textsc{Alloc}:& \quad (H, A, \texttt{open}(v)) \longrightarrow (H, A[r \mapsto \textsc{Live}], r) \quad r \text{ fresh} \\
\textsc{Use}:& \quad (H, A, \texttt{use}(r)) \longrightarrow (H, A, v) \quad \text{if } A(r) = \textsc{Live} \\
\textsc{Free}:& \quad (H, A, \texttt{close}(r)) \longrightarrow (H, A[r \mapsto \textsc{Freed}], ()) \\
\textsc{Move}:& \quad (H, A, \texttt{send}(\textit{pid}, r)) \longrightarrow (H, A, ()) \quad \text{ownership transferred}
\end{align*}

A state is \emph{invalid} if any reduction attempts $\textsc{Use}$ or $\textsc{Free}$ on $r$ where $A(r) = \textsc{Freed}$, or if $r$ has been moved and is subsequently referenced in the source context.
The type system's linearity discipline guarantees that for any well-typed program $e$, the reduction sequence from $(H_0, A_0, e)$ never reaches an invalid state: every resource identifier $r$ is used at most once after allocation, consumed exactly once by $\textsc{Free}$ or $\textsc{Move}$, and never accessed after consumption.
A full mechanized proof would proceed by induction on the typing derivation and case analysis on the reduction rules, following the structure of linear type soundness proofs in the literature~\citep{pierce2002types}.
\end{proof}

The practical implication is that \japl{} programmers write most code in a style identical to Erlang or Haskell---pure functions transforming immutable values---but gain Rust-level resource safety for the 10--15\% of code that interacts with external resources.

\subsection{Comparison with Alternative Approaches}

\begin{table}[H]
\centering
\scriptsize
\begin{tabularx}{\columnwidth}{lXXX}
\toprule
& \textbf{Data} & \textbf{Resources} & \textbf{Burden} \\
\midrule
Go & GC & GC + finalizers & Low, but leaks \\
Rust & Ownership & Ownership & High everywhere \\
Haskell & GC & GC + brackets & Low, but leaks \\
Erlang & GC & Ports/NIFs & Low, but unsafe \\
\textbf{\japl{}} & \textbf{GC} & \textbf{Ownership} & \textbf{Low + safe} \\
\bottomrule
\end{tabularx}
\caption{Memory management strategies compared.}
\label{tab:memory-comparison}
\end{table}

% ============================================================
% 6. COMPILATION MODEL
% ============================================================
\section{Compilation Model}
\label{sec:compilation}

\japl{}'s compilation model is designed for the edit-compile-test loop, where the latency between saving a file and seeing test results is the critical metric.

\subsection{Architecture Overview}

The compilation pipeline proceeds through the following phases:

\begin{enumerate}
\item \textbf{Parsing} ($\BigO(n)$): Source text to AST. Each file is parsed independently and in parallel.
\item \textbf{Name resolution} ($\BigO(n \log n)$): Resolving imports, building the module dependency graph.
\item \textbf{Type checking and inference} ($\BigO(n)$ practical): Bidirectional type checking with local inference. Effect inference within function bodies; effect checking at module boundaries.
\item \textbf{Effect-aware optimization}: Dead code elimination, function inlining, and constant folding, guided by effect annotations.
\item \textbf{Code generation}: Cranelift (debug) or LLVM (release).
\item \textbf{Linking}: Static linking of all modules and the runtime into a single binary.
\end{enumerate}

\subsection{Whole-Program vs. Separate Compilation}

\japl{} uses a hybrid approach:

\begin{itemize}[leftmargin=*]
\item \textbf{Separate compilation for type checking:} Each module is type-checked against the \emph{signatures} of its dependencies, not their implementations. This enables parallel type checking and incremental recompilation.
\item \textbf{Whole-program optimization for code generation:} In release mode, the optimizer sees the entire program, enabling cross-module inlining, specialization, and dead code elimination.
\end{itemize}

This hybrid approach gets the best of both worlds: fast incremental builds during development (separate compilation) and aggressive optimization for production (whole-program).

\subsection{Incremental Strategies}

\japl{}'s incremental compilation uses a fine-grained dependency tracking system:

\begin{definition}[Interface Stability]
A module interface $I(M)$ consists of:
\begin{itemize}
\item Type definitions exported by $M$
\item Function signatures (including effect annotations) exported by $M$
\item Trait implementations provided by $M$
\end{itemize}
A change $\delta$ to module $M$ is \emph{interface-stable} if $I(M)$ is unchanged after applying $\delta$.
\end{definition}

\begin{proposition}[Incremental Recompilation Bound]
If a change $\delta$ to module $M$ is interface-stable, only $M$ itself needs recompilation.
The downstream modules that depend on $M$ need not be recompiled or even re-checked.
\end{proposition}

Effect annotations contribute to interface stability in an important way: if a function's implementation changes but its effect signature does not, downstream modules remain valid.
This is strictly better than languages without effect tracking, where any implementation change might introduce new side effects that callers should know about.

\subsection{How Effect Types Enable Optimization}

\begin{proposition}[Pure Function Optimization]
Functions annotated as $\text{Pure}$ (the default in \japl{}) admit the following optimizations that are unsound for effectful functions:
\begin{enumerate}
\item \textbf{Common subexpression elimination:} If $f$ is pure and $f(x)$ appears twice, the second occurrence can be replaced with the result of the first.
\item \textbf{Dead code elimination:} If the result of $f(x)$ is unused, the call can be eliminated.
\item \textbf{Reordering:} Calls to pure functions can be reordered freely.
\item \textbf{Memoization:} Results of pure functions can be cached.
\item \textbf{Parallelization:} Independent calls to pure functions can be evaluated in parallel.
\end{enumerate}
\end{proposition}

For effectful functions, the effect annotation provides partial optimization information:
\begin{itemize}
\item $\text{State}[s]$ functions can be reordered with respect to $\text{Io}$ functions (state is local).
\item $\text{Fail}[e]$ functions can be eliminated if wrapped in a handler that discards the result.
\item $\text{Net}$ functions cannot be reordered or eliminated (observable side effects).
\end{itemize}

\subsection{AOT vs. JIT Trade-offs}

\japl{} uses ahead-of-time (AOT) compilation exclusively, forgoing JIT compilation.
This decision is motivated by several factors:

\begin{enumerate}[leftmargin=*]
\item \textbf{Predictable performance.} AOT-compiled code has consistent performance characteristics from the first invocation. There is no warm-up period, no sudden deoptimizations, and no performance cliffs.
\item \textbf{Simpler deployment.} A statically compiled binary requires no JIT compiler, no runtime code cache management, and no W\^{}X memory permission considerations (relevant for security-hardened environments).
\item \textbf{Cross-compilation compatibility.} AOT compilation is inherently cross-compilation-friendly: the compiler generates code for the target architecture, period. JIT compilers typically require target-architecture JIT implementations.
\item \textbf{Container friendliness.} Static binaries produce minimal container images (potentially \texttt{FROM scratch} Docker images), reducing attack surface and image pull times.
\end{enumerate}

The trade-off is that \japl{} cannot perform profile-guided optimizations at runtime or specialize generic code based on observed type distributions.
We argue that this trade-off is acceptable because:
(a) AOT link-time optimization with profile-guided optimization (PGO) data from previous runs provides similar benefits;
(b) effect-type-guided optimization recovers many opportunities that JIT systems use runtime profiling to discover; and
(c) predictable performance is more valuable than peak performance for the server-side workloads \japl{} targets.

% ============================================================
% 7. TOOLING AS LANGUAGE FEATURE
% ============================================================
\section{Tooling as Language Feature}
\label{sec:tooling}

\japl{} treats tooling not as an ecosystem concern but as a language design concern.
Every tool ships with the compiler and is maintained by the core team.

\subsection{The Case for Integrated Tooling}

The fragmentation of tooling in languages like Haskell, Scala, and even Rust (where \texttt{rustfmt} was not part of the initial release) creates several problems:

\begin{enumerate}[leftmargin=*]
\item \textbf{Configuration proliferation.} When multiple tools exist, each has its own configuration format, and projects accumulate dotfiles: \texttt{.prettierrc}, \texttt{.eslintrc}, \texttt{.editorconfig}, \texttt{rustfmt.toml}, \texttt{clippy.toml}.
\item \textbf{Version skew.} Third-party tools may not support the latest language features, creating windows where newly added syntax cannot be formatted or linted.
\item \textbf{Onboarding friction.} New contributors must install and configure multiple tools beyond the compiler itself.
\item \textbf{CI complexity.} Each tool adds a CI step, potentially with its own failure modes and update cadence.
\end{enumerate}

\subsection{Built-in Formatter}

\texttt{japl fmt} is a deterministic formatter: given the same AST, it always produces the same output.
It has zero configuration options.
Every \japl{} project in the world looks the same.

The formatter is implemented as a library that the compiler also uses for error message formatting, ensuring consistency between the code the programmer writes and the code the compiler displays in diagnostics.

\subsection{Built-in Test Runner}

Tests are first-class syntactic constructs:

\begin{lstlisting}
module UserTest

import User.{create_user, validate_email}

test "valid email passes validation" {
  assert validate_email("alice@example.com")
    == Ok("alice@example.com")
}

test "missing @ is rejected" {
  assert validate_email("bad-email")
    == Err(InvalidEmail("bad-email"))
}

property "email roundtrip" {
  forall (local: AlphaString, domain: DomainString) ->
    let email = local ++ "@" ++ domain
    validate_email(email) == Ok(email)
}
\end{lstlisting}

Because tests are known to the compiler, it can:
\begin{itemize}[leftmargin=*]
\item Skip codegen for non-test code in test-only builds
\item Provide test-specific error messages that reference the assertion expression
\item Track test coverage at the expression level, not the line level
\item Run property-based tests with integrated shrinking
\end{itemize}

\subsection{Built-in Package Manager}

\texttt{japl deps} manages dependencies through a centralized registry with reproducible builds:

\begin{lstlisting}[language=shell]
$ japl deps add http 0.5
$ japl deps update
$ japl deps audit    # security audit
$ japl deps tree     # dependency tree
\end{lstlisting}

The lockfile format is deterministic and human-readable.
Dependency resolution uses a SAT solver to find compatible version sets, with clear error messages when resolution fails.

\subsection{Language Server Protocol}

\japl{} ships a Language Server Protocol (LSP) implementation that provides:
\begin{itemize}[leftmargin=*]
\item Hover information with types, effects, and documentation
\item Go-to-definition (including into standard library and dependencies)
\item Find-all-references
\item Rename refactoring
\item Inline diagnostics with fix suggestions
\item Effect signature display for any expression
\end{itemize}

The LSP server reuses the compiler's type-checking infrastructure, ensuring that IDE feedback is always consistent with compilation results.

\subsection{REPL}

\begin{lstlisting}[language=shell]
$ japl repl
japl> let xs = [1, 2, 3, 4, 5]
xs : List[Int] = [1, 2, 3, 4, 5]

japl> List.map(xs, fn x -> x * x)
[1, 4, 9, 16, 25] : List[Int]

japl> :type List.fold
List.fold : fn(List[a], b, fn(b, a) -> b) -> b

japl> :effects File.read_to_string
File.read_to_string : Io, Fail[IoError]
\end{lstlisting}

The REPL supports incremental compilation: each expression is compiled and executed in the context of previous definitions, with the same type checking and effect tracking as regular code.

\subsection{Built-in Profiler}

\begin{lstlisting}[language=shell]
$ japl run --profile myapp.japl
# After execution:
Top functions by time:
  1. Json.parse         312ms  (42.1%)
  2. Http.handle_req    198ms  (26.7%)
  3. Db.query           156ms  (21.0%)
  4. List.map            42ms   (5.7%)

Per-process GC statistics:
  Process <0.12.0>: 3 minor GCs, 0 major
  Process <0.47.0>: 12 minor GCs, 1 major
  Process <0.48.0>: 8 minor GCs, 0 major

Message passing:
  Total messages: 14,235
  Avg queue depth: 2.3
  Max queue depth: 47 (Process <0.47.0>)
\end{lstlisting}

Because the profiler is integrated with the runtime, it can provide process-aware, effect-aware profiling data that external profilers cannot: per-process allocation rates, message throughput between process pairs, supervision tree overhead, and effect handler costs.

% ============================================================
% 8. DEPLOYMENT
% ============================================================
\section{Deployment}
\label{sec:deployment}

Deployment is where operational simplicity pays its largest dividends.
A language can have the most beautiful type system in the world, but if deploying it requires a Ph.D. in systems administration, it will not be adopted for production use.

\subsection{Static Binaries}

Every \japl{} build produces a single statically linked binary.
The binary includes:
\begin{itemize}[leftmargin=*]
\item The application code (compiled to native machine code)
\item The \japl{} runtime (process scheduler, GC, network event loop)
\item The standard library (only functions actually used, thanks to dead code elimination)
\item A minimal C runtime (for system calls)
\end{itemize}

No shared libraries, no virtual machine, no interpreter, no runtime downloads.

\subsection{Cross-Compilation Matrix}

\japl{} supports cross-compilation for all major targets from any development platform:

\begin{table}[H]
\centering
\scriptsize
\begin{tabular}{lccc}
\toprule
\textbf{Target} & \textbf{From Linux} & \textbf{From macOS} & \textbf{From Windows} \\
\midrule
linux-amd64 & \checkmark & \checkmark & \checkmark \\
linux-arm64 & \checkmark & \checkmark & \checkmark \\
darwin-amd64 & \checkmark & \checkmark & \checkmark \\
darwin-arm64 & \checkmark & \checkmark & \checkmark \\
windows-amd64 & \checkmark & \checkmark & \checkmark \\
wasm32 & \checkmark & \checkmark & \checkmark \\
\bottomrule
\end{tabular}
\caption{Cross-compilation support matrix.}
\label{tab:cross-compilation}
\end{table}

\subsection{Container-Friendly Builds}

\japl{}'s static binaries enable minimal container images:

\begin{lstlisting}[language=shell,basicstyle=\ttfamily\tiny]
# Multi-stage build
FROM japl:latest AS builder
COPY . /app
RUN japl build --release --static /app/main.japl

# Final image: just the binary
FROM scratch
COPY --from=builder /app/main /main
ENTRYPOINT ["/main"]
\end{lstlisting}

The resulting image contains only the application binary---no OS, no package manager, no shell.
This produces images in the 5--20 MB range (depending on application size), compared to 100+ MB for typical Go images, 200+ MB for Rust images with a Debian base, and 500+ MB for Haskell images.

\subsection{Minimal Runtime Dependencies}

\japl{} binaries have zero runtime dependencies beyond the operating system kernel.
Specifically, they do not require:
\begin{itemize}[leftmargin=*]
\item A C standard library (system calls are made directly)
\item DNS resolver libraries (a pure-\japl{} DNS client is included in the runtime)
\item TLS libraries (a pure-\japl{} TLS implementation is included)
\item Any \texttt{.so}/\texttt{.dylib}/\texttt{.dll} files
\end{itemize}

This eliminates the ``works on my machine'' class of deployment failures that arise from shared library version mismatches.

\subsection{Deployment Comparison}

\begin{table}[H]
\centering
\scriptsize
\begin{tabularx}{\columnwidth}{lXXXXX}
\toprule
& \textbf{\japl{}} & \textbf{Go} & \textbf{Rust} & \textbf{Haskell} & \textbf{Erlang} \\
\midrule
Artifact & Binary & Binary & Binary & Binary & Release \\
Deps & None & libc & libc* & Many & BEAM \\
Image & 5--20MB & 10--30MB & 5--30MB & 200+MB & 100+MB \\
Cross & Trivial & Trivial & Moderate & Hard & N/A \\
\bottomrule
\end{tabularx}
\caption{Deployment characteristics. (*Rust can statically link musl libc.)}
\label{tab:deployment}
\end{table}

% ============================================================
% 9. COMPARISON
% ============================================================
\section{Comparison with Existing Languages}
\label{sec:comparison}

We now provide a detailed comparison of \japl{} against five languages that each represent a different point in the design space.

\subsection{Go: Gold Standard for Tooling, Weak Types}

Go~\citep{pike2012go,donovan2015go} is the language \japl{} most admires operationally and most disagrees with type-theoretically.

\textbf{What Go gets right:}
\begin{itemize}[leftmargin=*]
\item Compilation speed (seconds for large projects)
\item Single static binary deployment
\item Canonical formatter (\texttt{gofmt})
\item Unified toolchain (\texttt{go build/test/vet/doc})
\item Cross-compilation via \texttt{GOOS}/\texttt{GOARCH}
\item Excellent standard library for networking
\end{itemize}

\textbf{What Go gives up:}
\begin{itemize}[leftmargin=*]
\item No algebraic data types (sum types). Error handling is \texttt{if err != nil} repeated \emph{ad nauseam}.
\item No exhaustive pattern matching. Missing cases are silent bugs.
\item No generics until Go 1.18, and the resulting generics are limited.
\item No effect tracking. Any function might perform I/O.
\item Shared mutable memory with goroutines creates data race possibilities.
\item No supervision trees. Goroutine failures are unobserved by default.
\end{itemize}

\japl{} aims to match Go's operational excellence while providing the type safety that Go lacks.
The key insight is that ADTs, traits, effect types, and pattern matching do not inherently require slow compilation---their type-checking algorithms are well within the decidable, practically-fast region of the complexity hierarchy.

\subsection{Rust: Powerful but Slow Compilation}

Rust~\citep{matsakis2014rust,klabnik2019rust} provides the strongest compile-time guarantees of any mainstream language, at significant cost.

\textbf{What Rust gets right:}
\begin{itemize}[leftmargin=*]
\item Ownership and borrowing eliminate memory safety bugs
\item Zero-cost abstractions
\item Excellent pattern matching and enums
\item Trait-based generics
\item Growing ecosystem (crates.io)
\end{itemize}

\textbf{What Rust gives up:}
\begin{itemize}[leftmargin=*]
\item Compilation speed: 10+ minutes for medium projects is common
\item Cognitive overhead: lifetime annotations pervade the codebase
\item No lightweight processes (async/await is complex)
\item No supervision or fault tolerance primitives
\item No effect tracking (beyond \texttt{unsafe})
\item Steep learning curve, particularly for the borrow checker
\end{itemize}

\japl{} borrows Rust's ownership model for resources but applies it only where needed (external resources), keeping the common case (pure functional code) free of lifetime annotations.

\subsection{Haskell: Powerful Types, Deployment Nightmare}

Haskell~\citep{marlow2010haskell,jones2003haskell} is the purest realization of the ``types first'' philosophy, and its deployment story illustrates the cost of neglecting operational concerns.

\textbf{What Haskell gets right:}
\begin{itemize}[leftmargin=*]
\item The most expressive type system in mainstream use
\item Purity enforced by the type system
\item Algebraic data types and pattern matching
\item Type classes and higher-kinded types
\item Lazy evaluation enables elegant abstractions
\end{itemize}

\textbf{What Haskell gives up:}
\begin{itemize}[leftmargin=*]
\item Compilation speed: GHC is slow, especially with extensions
\item Deployment: dynamic linking, platform-specific builds, large executables
\item Space leaks from lazy evaluation~\citep{mitchell2013leaking}
\item Unpredictable stack traces
\item Multiple build systems (Cabal, Stack, Nix)
\item IO monad creates a ``monad transformer stack'' complexity cliff
\end{itemize}

\japl{}'s effect system achieves Haskell-like purity tracking without monadic syntax overhead, and strict evaluation eliminates the space leak problem entirely.

\subsection{Erlang: Great Runtime, Weak Tooling}

Erlang~\citep{armstrong2003erlang,armstrong2007erlang} provides the runtime model that \japl{} most closely follows, while addressing its shortcomings.

\textbf{What Erlang gets right:}
\begin{itemize}[leftmargin=*]
\item Lightweight processes (millions per node)
\item Supervision trees and fault tolerance
\item Hot code loading
\item Runtime observability (\texttt{:observer}, tracing)
\item Distribution built in
\item Per-process GC
\end{itemize}

\textbf{What Erlang gives up:}
\begin{itemize}[leftmargin=*]
\item Dynamic typing: runtime type errors in production
\item No algebraic data types or exhaustive pattern matching
\item No resource safety (no ownership model)
\item Requires BEAM VM installation on target systems
\item Limited tooling (no canonical formatter until recently)
\item Unusual syntax discourages adoption
\end{itemize}

\japl{} combines Erlang's runtime model with static typing, static binaries, and modern tooling.

\subsection{OCaml: Good Balance, Ecosystem Gaps}

OCaml~\citep{leroy2014ocaml} is perhaps the closest existing language to \japl{}'s design philosophy, but with significant differences.

\textbf{What OCaml gets right:}
\begin{itemize}[leftmargin=*]
\item Fast compilation
\item Algebraic data types and pattern matching
\item Powerful module system (functors)
\item Good native code generation
\item Hindley-Milner type inference
\end{itemize}

\textbf{What OCaml gives up:}
\begin{itemize}[leftmargin=*]
\item No lightweight processes (until OCaml 5.0 with effects)
\item No supervision or distribution
\item No effect tracking (unrestricted mutation)
\item Smaller ecosystem than Go, Rust, or Haskell
\item Historically fragmented tooling (improved with dune and opam)
\item No cross-compilation story comparable to Go
\end{itemize}

\subsection{Summary}

\begin{table*}[t]
\centering
\scriptsize
\begin{tabular}{lccccccc}
\toprule
\textbf{Property} & \textbf{\japl{}} & \textbf{Go} & \textbf{Rust} & \textbf{Haskell} & \textbf{Erlang} & \textbf{OCaml} & \textbf{Gleam} \\
\midrule
ADTs + pattern matching & \checkmark & & \checkmark & \checkmark & Partial & \checkmark & \checkmark \\
Effect tracking & \checkmark & & Partial & \checkmark & & & \\
Ownership for resources & \checkmark & & \checkmark & & & & \\
Lightweight processes & \checkmark & \checkmark & & & \checkmark & Partial & \checkmark \\
Supervision trees & \checkmark & & & & \checkmark & & \checkmark \\
Fast compilation & \checkmark & \checkmark & & & \checkmark & \checkmark & \checkmark \\
Static binaries & \checkmark & \checkmark & \checkmark & Partial & & \checkmark & \\
Canonical formatter & \checkmark & \checkmark & \checkmark & & & \checkmark & \checkmark \\
Built-in test runner & \checkmark & \checkmark & \checkmark & & & & \\
Cross-compilation & \checkmark & \checkmark & \checkmark & & & & \\
Distribution & \checkmark & & & & \checkmark & & \checkmark \\
\bottomrule
\end{tabular}
\caption{Feature comparison across languages. \japl{} is the only language that achieves all properties simultaneously.}
\label{tab:full-comparison}
\end{table*}

% ============================================================
% 10. THE TYPE POWER BUDGET
% ============================================================
\section{The Type Power Budget}
\label{sec:type-power-budget}

Not all type system features are created equal.
Some provide enormous safety benefits at low complexity cost; others provide marginal benefits at high cost.
We formalize this observation as a \emph{type power budget}: a framework for evaluating whether a type system feature's safety contribution justifies its complexity.

\subsection{Formalization}

\begin{definition}[Type Feature]
A type feature $\phi$ is characterized by a tuple $(S_\phi, C_\phi, I_\phi)$ where:
\begin{itemize}
\item $S_\phi \in [0, 1]$ is the \emph{safety contribution}: the fraction of a representative bug taxonomy that $\phi$ prevents.
\item $C_\phi \in [0, 1]$ is the \emph{complexity cost}: a normalized measure of the cognitive overhead, compilation cost, and tooling difficulty that $\phi$ introduces.
\item $I_\phi \subseteq \Phi$ is the \emph{interaction set}: the set of other features whose complexity is affected by $\phi$'s presence.
\end{itemize}
\end{definition}

\begin{definition}[Safety-per-Complexity Ratio]
The safety-per-complexity ratio of a feature $\phi$ in the context of a feature set $F$ is:
\[
\rho(\phi, F) = \frac{S_\phi}{\displaystyle C_\phi + \sum_{\psi \in I_\phi \cap F} \Delta C_{\phi,\psi}}
\]
where $\Delta C_{\phi,\psi}$ is the additional complexity from the interaction between $\phi$ and $\psi$.
\end{definition}

\begin{definition}[Type Power Budget]
A type power budget $B$ is a threshold on the minimum acceptable ratio:
\[
F^* = \{\phi \in \Phi : \rho(\phi, F^*) \geq B\}
\]
The budget $B$ partitions the space of type features into those that earn their keep and those that do not.
\end{definition}

\subsection{Feature Evaluation}

We evaluate concrete type system features against \japl{}'s budget:

\begin{table}[H]
\centering
\scriptsize
\begin{tabularx}{\columnwidth}{lcccc}
\toprule
\textbf{Feature} & $S_\phi$ & $C_\phi$ & $\rho$ & \textbf{Include?} \\
\midrule
ADTs (sum types) & 0.85 & 0.15 & 5.67 & Yes \\
Pattern matching & 0.80 & 0.10 & 8.00 & Yes \\
Parametric poly. & 0.70 & 0.15 & 4.67 & Yes \\
Traits/type classes & 0.65 & 0.20 & 3.25 & Yes \\
Row polymorphism & 0.45 & 0.20 & 2.25 & Yes \\
Effect types & 0.60 & 0.25 & 2.40 & Yes \\
Linear types (res.) & 0.55 & 0.20 & 2.75 & Yes \\
\midrule
GADTs & 0.25 & 0.40 & 0.63 & No \\
Type families & 0.20 & 0.45 & 0.44 & No \\
Dependent types & 0.30 & 0.70 & 0.43 & No \\
HKTs (full) & 0.20 & 0.35 & 0.57 & No \\
\bottomrule
\end{tabularx}
\caption{Type feature evaluation. \japl{} includes features with $\rho \geq 2.0$.}
\label{tab:type-budget}
\end{table}

\subsection{What \japl{} Includes}

\begin{enumerate}[leftmargin=*]
\item \textbf{Algebraic data types.} Sum types and product types prevent null pointer errors, represent domain models precisely, and enable exhaustive pattern matching. The safety benefit is enormous; the complexity cost is low.

\item \textbf{Exhaustive pattern matching.} Catches missing cases at compile time. Negligible complexity cost for massive safety benefit.

\item \textbf{Parametric polymorphism.} Enables generic data structures and functions without sacrificing type safety. Well-understood, efficiently implementable.

\item \textbf{Traits (type classes).} Enable ad-hoc polymorphism (overloading) in a principled way. \japl{} restricts to single-parameter type classes without functional dependencies, keeping resolution decidable and predictable.

\item \textbf{Row polymorphism.} Enables structural subtyping for records without full subtype polymorphism. Allows writing functions that work on ``any record with a \texttt{name} field'' without inheritance.

\item \textbf{Effect types.} Track side effects in function signatures. Enable optimization (pure function elimination), documentation (what can this function do?), and safety (pure functions cannot perform I/O).

\item \textbf{Linear types for resources.} Ensure deterministic cleanup of external resources. Applied only to the resource layer, not to all values.
\end{enumerate}

\subsection{What \japl{} Excludes}

\begin{enumerate}[leftmargin=*]
\item \textbf{GADTs.} Generalized algebraic data types enable type-level programming but make type inference undecidable~\citep{jones2006gadts}. The practical use cases (length-indexed vectors, well-typed interpreters) do not justify the complexity for a general-purpose language.

\item \textbf{Type families.} Type-level functions add significant complexity to the type checker and are a common source of confusing error messages in Haskell. Most practical uses can be achieved with traits and associated types.

\item \textbf{Dependent types.} Full dependent types make type checking undecidable. While dependently typed languages like Agda~\citep{norell2007agda} and Idris~\citep{brady2013idris} are fascinating research vehicles, the complexity cost is prohibitive for a language targeting production use.

\item \textbf{Higher-kinded types (full).} \japl{} supports first-order type constructors (e.g., \texttt{List[a]}, \texttt{Option[a]}) but not higher-kinded types (e.g., a function parameterized over \texttt{f} where \texttt{f} is itself a type constructor). This limits some abstraction patterns (no generic ``Monad'' trait) but dramatically simplifies type inference and error messages.
The \texttt{Functor} trait is provided as a special case known to the compiler, rather than as a consequence of full HKT support.
\end{enumerate}

\subsection{The Budget as Design Discipline}

The type power budget is not a mathematical formula applied mechanically; the $S_\phi$ and $C_\phi$ values in \Cref{tab:type-budget} are design-team estimates informed by experience, not objective constants derived from empirical measurement.
Reasonable practitioners may assign different values---for instance, proponents of strongly-typed DSLs would likely rate GADTs' safety contribution higher than 0.25.
The budget's value is as a \emph{design discipline}: it forces the question ``what safety problem does this feature solve, and at what cost?'' for every proposed addition to the type system.

This discipline prevents feature creep---the gradual accumulation of type system features that individually seem justified but collectively produce an incomprehensible language.
Haskell's GHC has over 100 language extensions, many of which interact in surprising ways.
\japl{}'s type power budget is explicitly designed to avoid this outcome.

% ============================================================
% 11. OBSERVABILITY
% ============================================================
\section{Observability}
\label{sec:observability}

Runtime observability is a first-class design concern in \japl{}, not a third-party concern delegated to APM vendors.

\subsection{Built-in Tracing}

\japl{}'s runtime includes a distributed tracing system compatible with the OpenTelemetry standard~\citep{opentelemetry2023}:

\begin{lstlisting}
fn handle_request(req: Request)
    -> Response with Io, Net, Trace =
  Trace.span("handle_request", fn ->
    let user = Trace.span("auth", fn ->
      authenticate(req)?
    )
    let data = Trace.span("fetch_data", fn ->
      fetch_user_data(user.id)?
    )
    Response.json(200, data)
  )
\end{lstlisting}

Traces propagate across process boundaries and across nodes in a distributed cluster.
The tracing system is built into the runtime, so it can capture process-level events (spawn, crash, restart) in addition to application-level spans.

\subsection{Structured Logging}

\begin{lstlisting}
fn process_order(order: Order)
    -> Result[Receipt, OrderError] with Io, Log =
  Log.info("Processing order",
    [("order_id", order.id),
     ("items", show(List.length(order.items))),
     ("total", show(order.total))])
  let result = validate_and_charge(order)?
  Log.info("Order completed",
    [("order_id", order.id),
     ("receipt_id", result.id)])
  Ok(result)
\end{lstlisting}

Logging is an effect (\texttt{Log}), which means:
\begin{itemize}[leftmargin=*]
\item Pure functions cannot log (they have no effect annotation for it)
\item Log output can be captured and tested
\item Log handlers can be swapped (e.g., JSON output for production, human-readable for development)
\end{itemize}

\subsection{Process Inspection}

\begin{lstlisting}
fn debug_system() -> Unit with Io =
  let procs = Process.list()
  procs |> List.each(fn p ->
    let info = Process.info(p)
    print("PID: " <> show(p.id)
      <> " status: " <> show(info.status)
      <> " msgs: " <> show(info.message_queue_len)
      <> " mem: " <> show(info.memory))
  )
\end{lstlisting}

At runtime, any process can inspect:
\begin{itemize}[leftmargin=*]
\item The list of all running processes
\item Each process's status, message queue length, memory usage, and current function
\item The supervision tree structure
\item Link and monitor relationships
\end{itemize}

This is directly inspired by Erlang's \texttt{:observer} and \texttt{:sys} modules, adapted for a statically typed context.

\subsection{Runtime Metrics}

The runtime exports metrics in a standard format (Prometheus-compatible):
\begin{itemize}[leftmargin=*]
\item \texttt{japl\_process\_count}: number of active processes
\item \texttt{japl\_message\_total}: total messages sent
\item \texttt{japl\_gc\_pause\_seconds}: GC pause durations (per process)
\item \texttt{japl\_scheduler\_utilization}: CPU utilization per scheduler thread
\item \texttt{japl\_memory\_heap\_bytes}: total immutable heap size
\item \texttt{japl\_memory\_arena\_bytes}: total resource arena size
\end{itemize}

These metrics are available without any application code, because they are generated by the runtime itself.

% ============================================================
% 12. CASE STUDY
% ============================================================
\section{Case Study: Building, Testing, and Deploying a Service}
\label{sec:case-study}

We compare the experience of building, testing, and deploying a representative microservice---an HTTP API with database access, background job processing, and health monitoring---across five languages.

\subsection{Service Description}

The service implements:
\begin{enumerate}
\item An HTTP API with CRUD endpoints for a ``users'' resource
\item Database access (PostgreSQL) with connection pooling
\item A background job processor for sending welcome emails
\item Health checking and readiness probes
\item Structured logging and distributed tracing
\item Graceful shutdown
\end{enumerate}

\subsection{Implementation: JAPL}

\begin{lstlisting}
module Main

import Http.{Server, Router, Request, Response}
import Db.{Pool, query}
import Job.{Runner, enqueue}
import Log
import Trace

fn main() -> Unit with Io, Net, Process =
  let config = load_config()?
  let app = Supervisor.start(
    strategy = OneForOne,
    children = [
      child("db_pool",
        fn -> Pool.start(config.database)),
      child("job_runner",
        fn -> Runner.start(config.jobs)),
      child("http",
        fn -> Server.start(config.http, routes())),
    ]
  )
  Process.monitor(app)
  Process.receive()  -- block until shutdown

fn routes() -> Router =
  Router.new()
  |> Router.get("/health", health_handler)
  |> Router.get("/users/:id", get_user)
  |> Router.post("/users", create_user)

fn create_user(req: Request)
    -> Response with Io, Net, Trace =
  Trace.span("create_user", fn ->
    let params = Request.json_body(req)?
    let user = query("INSERT INTO users ...",
                     [params.name, params.email])?
    enqueue(SendWelcomeEmail(user))?
    Response.json(201, User.to_json(user))
  )

test "create user validates email" {
  let req = Request.mock(Post, "/users",
    Json.object([("name", "Alice"),
                 ("email", "bad")]))
  let resp = create_user(req)
  assert resp.status == 400
}
\end{lstlisting}

\subsection{Quantitative Comparison}

\begin{table}[H]
\centering
\scriptsize
\begin{tabularx}{\columnwidth}{lXXXXX}
\toprule
\textbf{Metric} & \textbf{\japl{}} & \textbf{Go} & \textbf{Rust} & \textbf{Haskell} & \textbf{Erlang} \\
\midrule
Lines of code & 420 & 580 & 750 & 510 & 480 \\
Build time (clean) & 3s & 2s & 180s & 120s & 4s \\
Build time (incr.) & 0.4s & 0.3s & 12s & 15s & 0.5s \\
Binary size & 12MB & 14MB & 8MB & 45MB & N/A \\
Docker image & 12MB & 22MB & 15MB & 280MB & 120MB \\
Dependencies & 3 & 8 & 15 & 22 & 5 \\
Config files & 1 & 3 & 4 & 5 & 3 \\
Test setup & 0 & 1 file & 1 file & 2 files & 1 file \\
\midrule
Null safety & \checkmark & & \checkmark & \checkmark & \\
Exhaustive match & \checkmark & & \checkmark & \checkmark & \\
Effect tracking & \checkmark & & & \checkmark & \\
Supervision & \checkmark & & & & \checkmark \\
Resource safety & \checkmark & & \checkmark & & \\
\bottomrule
\end{tabularx}
\caption{Quantitative comparison for the case study service. \japl{} figures are projected targets based on Cranelift code generation benchmarks and comparable OCaml/Gleam compilation speeds, not measurements from a mature production compiler. Figures for Go, Rust, Haskell, and Erlang are based on comparable real-world projects.}
\label{tab:case-study}
\end{table}

\subsection{Qualitative Observations}

\textbf{Go} requires the most boilerplate: explicit \texttt{if err != nil} error handling, manual struct-to-JSON mapping without sum types, and manual goroutine lifecycle management.
However, the development cycle is extremely fast and deployment is trivial.

\textbf{Rust} produces the smallest, fastest binary but has the longest build times by an order of magnitude.
The borrow checker adds friction to database connection pool management, requiring \texttt{Arc<Mutex<T>>} patterns that \japl{}'s process model avoids entirely.
Setting up async requires choosing between Tokio, async-std, and smol runtimes.

\textbf{Haskell} has the most concise business logic (thanks to monadic composition) but the most complex setup.
Building a deployable binary requires navigating Stack/Cabal configuration, and the resulting binary is large due to GHC's runtime.
Space leaks in the background job processor required profiling with GHC's heap profiler.

\textbf{Erlang} provides the best fault tolerance out of the box (supervision trees, hot code loading) but dynamic typing means type errors surface at runtime.
The background job processor can be updated without downtime.
However, deploying to containers requires including the entire BEAM runtime.

\textbf{\japl{}} combines Go's build speed and deployment simplicity with Erlang's fault tolerance and Haskell's type safety.
The supervision tree handles process failures automatically, the type system catches missing error cases at compile time, and the single static binary deploys trivially.

\subsection{Deployment Workflow}

The complete deployment workflow for the \japl{} service:

\begin{lstlisting}[language=shell]
$ japl test
  23 tests passed (0.8s)
  3 properties checked (1.2s, 100 cases each)

$ japl build --release --static \
    --target linux-amd64

$ docker build -t myservice:v1.2.0 .
  Step 1/3: FROM scratch
  Step 2/3: COPY main /main
  Step 3/3: ENTRYPOINT ["/main"]
  Built: 12.3MB

$ docker push myservice:v1.2.0
$ kubectl set image deploy/myservice \
    myservice=myservice:v1.2.0
\end{lstlisting}

Total time from code change to production: under 30 seconds for the build-test-package cycle, with no configuration files modified, no shared library concerns, and no runtime version compatibility issues.

% ============================================================
% 13. DISCUSSION
% ============================================================
\section{Discussion}
\label{sec:discussion}

\subsection{Is This Just Go with Better Types?}

A natural reaction to \japl{}'s design is to dismiss it as ``Go with algebraic data types.''
This characterization, while superficially plausible, misses several fundamental differences:

\begin{enumerate}[leftmargin=*]
\item \textbf{Process model.} \japl{}'s concurrency model is Erlang-style processes, not Go-style goroutines. The difference is not cosmetic: \japl{} processes have isolated heaps, typed mailboxes, and supervision trees. Goroutines share memory by default and have no recovery mechanism beyond \texttt{defer}/\texttt{recover}.

\item \textbf{Effect tracking.} \japl{}'s effect system provides information that Go's type system cannot express. Knowing that a function is pure enables optimizations, testing strategies, and compositional reasoning that are impossible when any function might perform I/O.

\item \textbf{Hybrid memory model.} Go uses a single GC for everything, including resources that would benefit from deterministic cleanup. \japl{}'s dual-layer model provides GC convenience for data and ownership precision for resources.

\item \textbf{Distribution.} \japl{}'s process model extends naturally to distributed systems with location-transparent PIDs and type-derived serialization. Go has no built-in distribution model.
\end{enumerate}

\subsection{Can This Scale?}

A reasonable concern is whether \japl{}'s compilation speed targets are achievable given a type system substantially more complex than Go's.

We argue yes, based on the following observations:
\begin{enumerate}[leftmargin=*]
\item OCaml already demonstrates that algebraic data types, parametric polymorphism, and Hindley-Milner inference compile fast.
\item Gleam compiles quickly to BEAM bytecode despite having ADTs and pattern matching.
\item \japl{}'s type system is deliberately bounded: by excluding GADTs, type families, and dependent types, we avoid the features that make GHC slow.
\item Effect inference is a local analysis within function bodies, not a global analysis.
\item The dual-backend strategy (Cranelift for dev, LLVM for release) ensures that development builds are always fast.
\end{enumerate}

\subsection{What About Hot Code Loading?}

Erlang's hot code loading---deploying new code without stopping the system---is one of its most celebrated features.
\japl{} does not support hot code loading in its initial design, for several reasons:

\begin{enumerate}[leftmargin=*]
\item Hot code loading conflicts with static typing: changing a function's type signature requires recompiling all callers, which is difficult to do atomically at runtime.
\item Modern deployment practices (rolling updates, blue-green deployments, canary releases) provide similar zero-downtime guarantees without the complexity of runtime code replacement.
\item Static binaries and fast builds enable rapid redeployment that achieves the same practical goal.
\end{enumerate}

Hot code loading remains a potential future extension for specific use cases (e.g., long-running telecom systems where even millisecond interruptions are unacceptable).

\subsection{Limitations}

\japl{}'s design involves genuine trade-offs:

\begin{enumerate}[leftmargin=*]
\item \textbf{No dependent types.} Some correctness properties (e.g., ``this list has exactly $n$ elements'') cannot be expressed in \japl{}'s type system. Programs requiring such guarantees must use runtime checks.
\item \textbf{GC pauses.} The immutable heap is garbage-collected, and GC introduces pause times. Per-process heaps limit the impact, but latency-critical applications may need to carefully manage process heap sizes.
\item \textbf{No shared mutable memory.} For workloads that genuinely benefit from shared-memory parallelism (e.g., large-scale numerical computation), \japl{}'s process model incurs message-passing overhead. An FFI to Rust or C is the escape hatch for such cases.
For high-performance networking scenarios requiring zero-copy shared buffers (e.g., kernel-mapped ring buffers shared between processes), \japl{} provides an \texttt{unsafe foreign} block that permits the creation of shared memory regions outside the ownership system.
Code within \texttt{unsafe foreign} blocks is explicitly excluded from the compiler's safety guarantees and must be audited manually, analogous to Rust's \texttt{unsafe} blocks.
This escape hatch is intentionally inconvenient to discourage casual use while remaining available for performance-critical FFI interoperation.
\item \textbf{Young ecosystem.} A new language cannot match the library ecosystems of established languages. \japl{} mitigates this with a comprehensive standard library and FFI, but third-party libraries will take time to develop.
\end{enumerate}

% ============================================================
% 14. RELATED THEORETICAL WORK
% ============================================================
\section{Related Theoretical Work}
\label{sec:related-theory}

\subsection{Abstract Machines and Cost Semantics}

\japl{}'s predictable execution model is informed by work on cost semantics for functional languages.
Blelloch and Greiner~\citep{blelloch1996cost} developed cost semantics for parallel functional programs, providing a framework for reasoning about work and span.
\japl{}'s strict evaluation ensures that cost semantics are straightforward: the cost of evaluating an expression is the sum of the costs of evaluating its subexpressions, with no hidden costs from lazy thunk evaluation.

The CESK machine~\citep{felleisen1986cesk} provides a foundational abstract machine model.
\japl{}'s runtime can be understood as a collection of CESK machines (one per process) communicating via message passing, with a work-stealing scheduler~\citep{blumofe1999cilk} distributing machines across OS threads.

\subsection{Real-Time Garbage Collection}

Baker's work on real-time garbage collection~\citep{baker1978gc} and subsequent developments in concurrent GC~\citep{jones2016gc} inform \japl{}'s per-process GC design.
The key insight is that per-process heaps bound GC pause times by bounding heap sizes: a process's heap is proportional to its live data, not to the total system's live data.

\subsection{Work-Stealing Schedulers}

\japl{}'s process scheduler is based on the work-stealing paradigm~\citep{blumofe1999cilk}, adapted for the Erlang-style process model.
Each OS thread maintains a local run queue of \japl{} processes; when a thread's queue is empty, it steals from another thread's queue.
This provides load balancing without a centralized scheduler, enabling scalability to many cores.

\subsection{Process Algebra}

\japl{}'s process model can be formalized in the $\pi$-calculus~\citep{milner1999pi}, with typed mailboxes corresponding to typed channels.
The restriction to single-mailbox processes (rather than multi-channel communication) simplifies the model while retaining sufficient expressiveness for practical concurrent programming.
Kobayashi's work on type systems for the $\pi$-calculus~\citep{kobayashi2005type} provides theoretical foundations for \japl{}'s typed process communication.

\paragraph{Typed Mailbox Variance and Protocol Evolution.}
\japl{}'s typed mailboxes use \emph{contravariant} input types: a process that can handle messages of type \texttt{A | B} can be safely referenced as \texttt{Pid[A]}, since it accepts at least \texttt{A}.
This follows standard subtyping for input channels in the $\pi$-calculus.
For protocol evolution---the common need to extend a running system's message vocabulary---\japl{} uses \emph{open union types} via row polymorphism: a mailbox type \texttt{Pid[\{Ping, Pong | r\}]} accepts at least \texttt{Ping} and \texttt{Pong} but is polymorphic in the remaining messages \texttt{r}.
A process can be upgraded to handle additional message variants without breaking existing senders, because the old type is a subtype of the new type under row extension.
This avoids the difficulties encountered by Akka Typed's ``behavior narrowing'' approach, where protocol changes required rewriting the entire actor hierarchy's types.

% ============================================================
% 15. CONCLUSION
% ============================================================
\section{Conclusion}
\label{sec:conclusion}

We have presented the design philosophy behind \japl{}'s seventh core principle: \emph{Runtime Simplicity Matters as Much as Type Power}.
This principle is not a compromise or a concession to practicality; it is a recognition that the purpose of a programming language is to build and deploy reliable software, and that type system expressiveness is one tool among many for achieving that goal.

The key insights of this paper are:

\begin{enumerate}[leftmargin=*]
\item \textbf{The type power budget.} Type system features should be evaluated by their safety-per-complexity ratio. ADTs, pattern matching, traits, effect types, and targeted linear types pass this test; GADTs, type families, and dependent types do not, for a production-oriented language.

\item \textbf{The hybrid memory model.} GC for immutable data and ownership for resources is the sweet spot: it provides Erlang-like ease for the common case and Rust-like precision where it matters.

\item \textbf{Tooling is a language feature.} A single canonical formatter, test runner, package manager, and profiler, all shipping with the compiler, eliminates an entire category of friction that plagues languages with fragmented ecosystems.

\item \textbf{Deployment is a design concern.} Static binaries, cross-compilation, and minimal runtime dependencies should be designed in from the start, not retrofitted.

\item \textbf{Effect types enable optimization and simplicity simultaneously.} Tracking effects in the type system provides both safety (knowing what a function can do) and optimization opportunities (eliminating pure computations whose results are unused), creating a virtuous cycle where type system features improve rather than degrade operational quality.
\end{enumerate}

The programming language community has a tendency to evaluate languages on a single axis: type system expressiveness.
This paper argues for a multi-dimensional evaluation that includes compilation speed, deployment simplicity, tooling quality, runtime predictability, and observability.
\japl{} is designed to score well on all dimensions simultaneously, demonstrating that the Pareto frontier of type safety and operational simplicity is not only reachable but worth reaching.

We believe that the next generation of successful programming languages will be defined not by how much they can express in their type systems, but by how effectively they bridge the gap between ``this program type-checks'' and ``this program is running reliably in production.''

% ============================================================
% REFERENCES
% ============================================================
\bibliographystyle{plainnat}

\begin{thebibliography}{40}

\bibitem[Allwood et~al.(2009)]{allwood2009stack-traces}
Allwood, T.~O., Sheridan, K., and Jones, S.~P.
\newblock Finding the needle: Stack traces for GHC.
\newblock In \emph{Proceedings of the Haskell Symposium}, pp.~129--140, 2009.

\bibitem[Armstrong(2003)]{armstrong2003erlang}
Armstrong, J.
\newblock Making reliable distributed systems in the presence of software errors.
\newblock PhD thesis, Royal Institute of Technology, Stockholm, 2003.

\bibitem[Armstrong(2007)]{armstrong2007erlang}
Armstrong, J.
\newblock \emph{Programming Erlang: Software for a Concurrent World}.
\newblock Pragmatic Bookshelf, 2007.

\bibitem[Baker(1978)]{baker1978gc}
Baker, H.~G.
\newblock List processing in real time on a serial computer.
\newblock \emph{Communications of the ACM}, 21(4):280--294, 1978.

\bibitem[Blelloch \& Greiner(1996)]{blelloch1996cost}
Blelloch, G.~E. and Greiner, J.
\newblock Parallelism in sequential functional languages.
\newblock In \emph{Proceedings of FPCA '95}, pp.~226--237, 1996.

\bibitem[Blumofe \& Leiserson(1999)]{blumofe1999cilk}
Blumofe, R.~D. and Leiserson, C.~E.
\newblock Scheduling multithreaded computations by work stealing.
\newblock \emph{Journal of the ACM}, 46(5):720--748, 1999.

\bibitem[Brady(2013)]{brady2013idris}
Brady, E.
\newblock Idris, a general-purpose dependently typed programming language: Design and implementation.
\newblock \emph{Journal of Functional Programming}, 23(5):552--593, 2013.

\bibitem[Bytecode Alliance(2020)]{cranelift2020}
Bytecode Alliance.
\newblock Cranelift code generator.
\newblock \url{https://cranelift.dev/}, 2020.

\bibitem[Donovan \& Kernighan(2015)]{donovan2015go}
Donovan, A.~A.~A. and Kernighan, B.~W.
\newblock \emph{The Go Programming Language}.
\newblock Addison-Wesley, 2015.

\bibitem[Felleisen \& Friedman(1986)]{felleisen1986cesk}
Felleisen, M. and Friedman, D.~P.
\newblock Control operators, the SECD-machine, and the $\lambda$-calculus.
\newblock In \emph{Formal Description of Programming Concepts III}, pp.~193--219, 1986.

\bibitem[Gleam(2023)]{gleam2023}
Gleam Team.
\newblock The Gleam programming language.
\newblock \url{https://gleam.run/}, 2023.

\bibitem[Griesemer et~al.(2020)]{griesemer2020generics}
Griesemer, R., Hu, R., Kokke, W., Lange, J., Taylor, I.~L., Toninho, B., Wadler, P., and Yoshida, N.
\newblock Featherweight Go.
\newblock In \emph{Proceedings of OOPSLA}, 2020.

\bibitem[Happi(2023)]{happi2023beam}
Happi, E.
\newblock \emph{The BEAM Book: Understanding the Erlang Runtime System}.
\newblock O'Reilly Media, 2023.

\bibitem[Ierusalimschy et~al.(2006)]{ierusalimschy2006lua}
Ierusalimschy, R., de~Figueiredo, L.~H., and Celes, W.
\newblock Lua 5.1 reference manual.
\newblock Technical report, Lua.org, 2006.

\bibitem[Jones(2003)]{jones2003haskell}
Jones, S.~P.
\newblock Haskell 98 language and libraries: The revised report.
\newblock \emph{Journal of Functional Programming}, 13(1):0--255, 2003.

\bibitem[Jones et~al.(2006)]{jones2006gadts}
Jones, S.~P., Vytiniotis, D., Weirich, S., and Washburn, G.
\newblock Simple unification-based type inference for GADTs.
\newblock In \emph{Proceedings of ICFP}, pp.~50--61, 2006.

\bibitem[Jones \& Hosking(2016)]{jones2016gc}
Jones, R., Hosking, A., and Moss, E.
\newblock \emph{The Garbage Collection Handbook: The Art of Automatic Memory Management}.
\newblock Chapman and Hall/CRC, 2nd edition, 2016.

\bibitem[Kelley(2020)]{kelley2020zig}
Kelley, A.
\newblock Zig: A language for system programming.
\newblock \url{https://ziglang.org/}, 2020.

\bibitem[Klabnik \& Nichols(2019)]{klabnik2019rust}
Klabnik, S. and Nichols, C.
\newblock \emph{The Rust Programming Language}.
\newblock No Starch Press, 2019.

\bibitem[Kobayashi(2005)]{kobayashi2005type}
Kobayashi, N.
\newblock Type-based information flow analysis for the pi-calculus.
\newblock \emph{Acta Informatica}, 42(4):291--347, 2005.

\bibitem[Lattner \& Adve(2004)]{lattner2004llvm}
Lattner, C. and Adve, V.
\newblock LLVM: A compilation framework for lifelong program analysis \& transformation.
\newblock In \emph{Proceedings of CGO}, pp.~75--86, 2004.

\bibitem[Leroy(2014)]{leroy2014ocaml}
Leroy, X.
\newblock The OCaml system: Documentation and user's manual.
\newblock Technical report, INRIA, 2014.

\bibitem[Marlow(2010)]{marlow2010haskell}
Marlow, S.
\newblock Haskell 2010 language report.
\newblock Technical report, haskell.org, 2010.

\bibitem[Matsakis \& Klock(2014)]{matsakis2014rust}
Matsakis, N.~D. and Klock, F.~S.
\newblock The Rust language.
\newblock In \emph{Proceedings of the ACM SIGAda Annual Conference on High Integrity Language Technology (HILT)}, pp.~103--104, 2014.

\bibitem[Matsakis(2016)]{matsakis2016incremental}
Matsakis, N.~D.
\newblock Incremental compilation.
\newblock Rust Blog, \url{https://blog.rust-lang.org/2016/09/08/incremental.html}, 2016.

\bibitem[McAdam(1998)]{mcadam1998complexity}
McAdam, B.~J.
\newblock On the unification of substitutions in type inference.
\newblock In \emph{Proceedings of the Implementation of Functional Languages Workshop}, 1998.

\bibitem[Milner(1999)]{milner1999pi}
Milner, R.
\newblock \emph{Communicating and Mobile Systems: The $\pi$-Calculus}.
\newblock Cambridge University Press, 1999.

\bibitem[Mitchell(2013)]{mitchell2013leaking}
Mitchell, N.
\newblock Leaking space: Detecting space leaks in Haskell programs.
\newblock In \emph{Proceedings of the Haskell Symposium}, 2013.

\bibitem[Norell(2007)]{norell2007agda}
Norell, U.
\newblock Towards a practical programming language based on dependent type theory.
\newblock PhD thesis, Chalmers University of Technology, 2007.

\bibitem[Odersky et~al.(2004)]{odersky2004scala}
Odersky, M., Altherr, P., Cremet, V., Emir, B., Maneth, S., Micheloud, S., Mihaylov, N., Schinz, M., Stenman, E., and Zenger, M.
\newblock An overview of the Scala programming language.
\newblock Technical Report IC/2004/64, EPFL, 2004.

\bibitem[OpenTelemetry(2023)]{opentelemetry2023}
OpenTelemetry Authors.
\newblock OpenTelemetry specification.
\newblock \url{https://opentelemetry.io/docs/specs/otel/}, 2023.

\bibitem[Pierce(2002)]{pierce2002types}
Pierce, B.~C.
\newblock \emph{Types and Programming Languages}.
\newblock MIT Press, 2002.

\bibitem[Pike(2012)]{pike2012go}
Pike, R.
\newblock Go at Google: Language design in the service of software engineering.
\newblock In \emph{Proceedings of SPLASH}, 2012.

\bibitem[Pike(2015)]{pike2015simplicity}
Pike, R.
\newblock Simplicity is complicated.
\newblock dotGo 2015, \url{https://www.youtube.com/watch?v=rFejpH_tAHM}, 2015.

\bibitem[Rust Survey(2023)]{rust-compile-survey-2023}
Rust Survey Team.
\newblock Annual Rust survey 2023 results.
\newblock \url{https://blog.rust-lang.org/2024/02/19/2023-Rust-Annual-Survey-2023-results.html}, 2023.

\bibitem[Snoyman(2017)]{snoyman2017haskell-deployment}
Snoyman, M.
\newblock Haskell's deployment problem.
\newblock FP Complete Blog, 2017.

\bibitem[Sulzmann et~al.(2007)]{sulzmann2007type-families}
Sulzmann, M., Chakravarty, M.~M.~T., Jones, S.~P., and Donnelly, K.
\newblock System F with type equality coercions.
\newblock In \emph{Proceedings of TLDI}, pp.~53--66, 2007.

\bibitem[Thompson(1984)]{thompson1984unix}
Thompson, K.
\newblock Reflections on trusting trust.
\newblock \emph{Communications of the ACM}, 27(8):761--763, 1984.

\bibitem[Waldo et~al.(1996)]{waldo1996distributed}
Waldo, J., Wyant, G., Wollrath, A., and Kendall, S.
\newblock A note on distributed computing.
\newblock Technical Report TR-94-29, Sun Microsystems Laboratories, 1996.

\bibitem[Wadler \& Blott(1989)]{wadler1989type-classes}
Wadler, P. and Blott, S.
\newblock How to make ad-hoc polymorphism less ad hoc.
\newblock In \emph{Proceedings of POPL}, pp.~60--76, 1989.

\bibitem[Wirth(1982)]{wirth1982modula2}
Wirth, N.
\newblock \emph{Programming in Modula-2}.
\newblock Springer-Verlag, 1982.

\bibitem[Ichbiah et~al.(1979)]{ichbiah1979ada}
Ichbiah, J.~D., Barnes, J.~G.~P., Heliard, J.~C., Krieg-Brueckner, B., Roubine, O., and Wichmann, B.~A.
\newblock Rationale for the design of the Ada programming language.
\newblock \emph{SIGPLAN Notices}, 14(6b):1--261, 1979.

\end{thebibliography}

\end{document}
