The J2 Programming Language
J2 is a small language with an unusual pair of properties: programs start instantly through an interpreter, and the same programs compile to native code that uses every core of your machine, without a single annotation.
You write plain code: constants and mutables, functions, sequences and maps, classes,
typed error handling. Running j2 on a file executes it immediately, with no
build step. When a program is compute heavy, j2 build produces a native
binary and recognizes the loops and independent calls that can safely run in parallel.
The result is scripting-language ergonomics with compiled-language speed where it
matters.
A first look
# Find the longest word.
words = ["apple", "banana", "fig", "grapefruit"]
func longest(ws) = {
best := ""
for w in ws {
if len(w) > len(best) { best = w }
}
give best
}
print(fmt("longest: {} ({} chars)", longest(words), len(longest(words))))
Five things J2 considers important are already visible here. Bindings are constant by
default (=) and mutable only when you say so (:=). Functions
return with give. Loops read like sentences. Text is formatted with
fmt and {} placeholders. And nothing here needed a type
annotation, although the language accepts them and rewards them with native speed.
What makes J2 different
Two engines, one behavior
J2 ships an interpreter and a native compiler in a single command. The interpreter gives you the immediacy of a scripting language; the compiler gives you machine code. Both are held to the same standard: a program must produce identical output on either engine, and the test suite runs every program on both to keep that promise honest.
Parallelism you do not write
Native builds recognize common shapes of compute: reductions over large sequences, element-wise loops, matrix times vector kernels, and functions that make several independent calls. When a shape is provably safe to split, the compiled program runs it across your cores. There are no threads, locks, or task APIs in the language at all. The Automatic Parallelism chapter explains exactly what fires and when.
Deny-by-default capabilities
A J2 program cannot touch the filesystem, spawn processes, or reach the network
unless you grant that capability on the command line. A script you downloaded cannot
quietly read your files; j2 report.j2 refuses, and
j2 --allow-fs report.j2 grants exactly one power. See
Command Line.
Self-contained toolchain
Installing J2 installs everything, including the native compiler and the libraries it links against. There is no package manager to configure and no network dependency at build time. A laptop with no development tools can compile J2 programs offline.
How these docs are organized
Getting Started installs the toolchain and walks through your first programs. The chapters under The Language cover J2 from the ground up and are written to be read in order, though each stands alone; together they document every construct in the language. The Reference section covers the standard library function by function, the command line, the parallelizer, and how the two execution engines work.
Examples in these pages are complete programs unless presented as fragments, and every complete example was run against J2 0.1.0 while building this site.