Skip to content
BFJ HelpBlock-based Featherweight Java
04 / Types

Every judgement, drawn as a proof

FJ's type system is small enough that its checker does not just accept or reject a program — it can show you the entire derivation for any expression you build, the way a paper would print it, and it never lets one unfinished socket paint the rest of the program red.

The type checker

fjTypeChecker.ts implements FJ's typing rules directly: T-Var, T-Field, T-Invk, T-New, and the three cast rules, alongside class and field well-formedness and FJ's override rule. Subtyping is nominal — class B is a subtype of A exactly when it declares extends A, transitively, with Object at the root.

Rule Judges
T-Var A variable, including this, looked up in Γ
T-Field e.f — the field's declared type on e's class
T-Invk e.m(ē) — the method's return type, with each argument checked against its parameter type
T-New new C(ē) — typed C, with each argument checked against the matching field's type
T-UCast An upcast — the target is a supertype of the source. Always safe.
T-DCast A downcast — the target is a subtype of the source. Safe if the runtime class actually matches; a stuck cast if it doesn't.
T-SCast A “stupid” cast — source and target are unrelated. Type-checks anyway, with a warning; see Problems below.

The override rule is stricter than it might look coming from ordinary Java: FJ has no overloading and no covariant returns, so an overriding method must match the inherited signature exactly — same parameter types, same return type, in the same order. There is exactly one legal signature for a given method name once a superclass has declared it.

Incomplete is not the same as wrong

An empty socket types as a first-class Hole, in the style of the Hazel language. A hole is consistent with everything, so it never cascades into the rest of the program: finish one field and leave a method body empty, and the field still checks cleanly while the empty method reports exactly one problem, not a wall of them. The whole workspace re-checks on every edit, and this is what makes that tolerable rather than noisy.

The Typing tab

The FJ Inspector's Typing tab renders a genuine natural-deduction proof tree for any expression: premises over a rule bar over a conclusion, each node showing the judgement Γ ⊢ e : C and the rule that produced it. Every node is clickable, and clicking one selects and centres the block it is about.

The BFJ Typing tab showing a natural-deduction proof tree for a stupid cast: T-New derives new B() : B, and T-SCast derives (A) new B() : A with a warning.
Fig. 1 The Stupid cast example, fully derived. T-New types the fresh B; T-SCast then types the cast to the unrelated A, flagged with a warning rather than a hard failure.

Loading Stupid cast and building it produces exactly this two-line derivation:

∅ ⊢ new B() : B          (T-New)
------------------------------------
∅ ⊢ (A) new B() : A       (T-SCast)

Read bottom-up as usual: the conclusion is (A) new B() : A, justified by T-SCast, whose single premise — new B() : B, justified by T-New — sits above the bar. Nothing about the tree hides that this is a cast between unrelated classes; the warning that goes with it lives in the Problems tab, not in the derivation.

The Problems tab

The bottom dock's Problems tab surfaces the same checker's diagnostics as a clickable list, and the same offending blocks get in-canvas warning-triangle icons. Loading and building Stupid cast produces exactly one entry: “Stupid cast: (A) applied to unrelated type B always fails at run time (T-SCast).”

That entry is shown as a warning, not an error. The program still type-checks and still runs — a stupid cast is a distinct, permitted rule in FJ's own type system, not a type error, and the Problems tab is honest about that distinction rather than flattening every diagnostic into red. What actually happens when you run it — a ClassCastException, not a crash — is the subject of Semantics § Stuck-but-safe casts.

BFJ is developed at L-Workshop. This help was written against the build running at bfj.l-workshop.my.id.