Jock
A Nock combinator language

Jock

Jock compiles a high-level syntax to Nock, the twelve-opcode combinator calculus underneath Nockchain and Urbit, among other platforms. Jock models its syntax on Swift and Rust, aiming to be more approachable than Hoon while still permitting direct expression of Nock concepts: classes, generics, pattern matching and operator traits, all the way down to raw nouns.

1. The public alpha is the original release, from zorp-corp.
2. Development of a release candidate continues in a successor repository (currently private), expanding the language's features and capabilities.

01 » Compiles to Nock

Every Jock program erases to a noun and a formula. Structs become right-nested tuples, unions become tagged cells, and the whole language bottoms out in twelve instructions.

Jock→ Nock
var a: Bool = true;
a = false;
a
compiles to
[8 [1 0] 7 [10 [2 1 1] 0 1] 0 2]
Write real Jock programs first, only meeting the Nock ISA noun underneath when it starts to matter.

02 » Examples

A few programs from the examples folder — each one a complete, executable program.

point.jock — operator traits on a sealed class
operator traits, classes, Real — p + q dispatches through class conformance
struct PointState { x: Real, y: Real };
class Point(PointState) impl Add, Sub {
  add(self: Self, p: Self) -> Self {
    Point{ x: self.x + p.x, y: self.y + p.y }
  };
  sub(self: Self, p: Self) -> Self {
    Point{ x: self.x - p.x, y: self.y - p.y }
  };
};
let p = Point{ x: 101.0, y: 105.0 };
let q = Point{ x: 42.0, y: 7.0 };
(p + q).x
sort.jock — generic insertion sort
bounded generics, T: Lt, operators as bounds — the same < becomes a trait call
func(T: Lt) insert(x: T, xs: List(T)) -> List(T) {
  match xs {
    (h, t) => if x < h { (x, xs) } else { (h, insert(x, t)) };
    _ => [x];
  }
};
func(T: Lt) isort(xs: List(T)) -> List(T) {
  match xs {
    (h, t) => insert(h, isort(t));
    _ => ~;
  }
};
isort([5, 3, 8, 1, 9, 2])
stoplight.jock — a state-machine kernel
a zero-ceremony NockApp kernel — the compiler synthesizes load/peek/poke from the Kernel protocol
union Color { red, green, yellow };
struct LightState { c: Color };
func advance(c: Color) -> Color {
  match c {
    red => Color.green;
    green => Color.yellow;
    yellow => Color.red;
  }
};
class Light(LightState) impl Kernel {
  load(self: Light, old: *) -> Light { old as! Light };
  peek(self: Light, p: *) -> * { self.c };
  poke(self: Light, e: *) -> (List(Effect), Light) {
    let n = advance(self.c);
    (~, Light{ c: n })
  };
};
Light{ c: Color.red }
counter.jock — the zero-ceremony counter kernel
impl Kernel, state threading — no driver, no import: this kernel builds and runs unchanged under jojo, the generic NockApp host
struct KS { n: @ };
class Counter(KS) impl Kernel {
  load(self: Counter, old: *) -> Counter { old as! Counter };
  peek(self: Counter, p: *) -> * { self.n };
  poke(self: Counter, e: *) -> (List(Effect), Counter) { (~, Counter{ n: self.n + 1 }) };
};
Counter{ n: 0 }
counter-v2.jock — the upgrade target for counter
load as migration — same host, a new state shape; load's as! carries counter's exported state into total
struct KS2 { n: @, total: @ };
class CounterV2(KS2) impl Kernel {
  load(self: CounterV2, old: *) -> CounterV2 { CounterV2{ n: old as! @, total: 100 } };
  peek(self: CounterV2, p: *) -> * { (self.n, self.total) };
  poke(self: CounterV2, e: *) -> (List(Effect), CounterV2) { (~, CounterV2{ n: self.n + 1, total: self.total + 1 }) };
};
CounterV2{ n: 0, total: 100 }

03 » Repositories

TrackRepositoryStatus
Alpha zorp-corp/jock-lang public (original release)
Recommenced sigilante/jock private (ongoing development)

Jock is a one-man rewrite in active development. The public alpha remains the reference for the original language release by Zorp in June 2025; new feature work is happening in the recommenced repository as of August 2026.

04 » Keywords

Every keyword in the frozen 1.0 grammar — kernel forms lower to one Nockasm production apiece, sugar rewrites to an AST already covered here — each with a minimal example.

KeywordSyntax
letlet x: @ = 5;
varvar b: @ = 0; b = b + 1;
funcfunc inc(n: @) -> @ { n + 1 };
lambdalet f = lambda(x: @) -> @ { x + 1 };
if / elseif a == 3 { 42 } else { 17 }
matchmatch a { %1 => 0; _ => 84; }
switchswitch a { 1 => 0; _ => 84; }
loop / recurloop { if a == b { b } else { b = b + 1; recur } }
evaleval(subj, form)
crash_ => crash;
importimport urbit;
as / as? / as!(n as? Char) ?? 'x'
assertassert n > 0;
printprint("count = {n}");
and / or / xor / notif a and not b { 1 } else { 0 }
structstruct PointState { x: Real, y: Real };
class / implclass Point(PointState) impl Arithmetic { … };
traittrait Arithmetic { add(self: Self, other: Self) -> Self; };
aliasalias Number Real;
unionunion Shape { point, circle(Real) };
inx in s

defer is reserved (%defer) but its runtime semantics aren't pinned yet, so it's left off the table above rather than shown with an invented example.