Control Flow in J
Learn control flow in J — conditionals, select/case, while and for loops, and the array-oriented and tacit alternatives that often replace them
Most languages treat control flow as the backbone of a program: you branch with if, you repeat with for and while, and you walk through data one element at a time. J supports all of these structures, but it also invites you to question whether you need them at all.
As an array-oriented language, J’s verbs apply to entire arrays at once. An operation you might write as a loop in Python—summing a list, filtering even numbers, transforming each element—usually collapses into a single expression with no explicit iteration. Loops still exist for genuinely sequential logic (accumulating state, early exit, stepwise algorithms), and J provides a full set of control words inside explicit definitions. But the idiomatic J solution often replaces a loop with an array operation or a tacit (point-free) conditional.
This tutorial covers both worlds. First the explicit control structures—if./elseif./else., select./case., while., and for.—and then the array-oriented and tacit techniques that frequently make them unnecessary. Along the way you’ll see why experienced J programmers reach for loops far less often than they did in other languages.
Conditionals: if. elseif. else. end.
J’s branching keywords end with a period and live inside an explicit definition. The form 3 : 0 begins a verb whose right argument is y; the body runs until a line containing only ).
Create a file named conditionals.ijs:
| |
Each branch is guarded by a condition followed by do., and the whole structure closes with end.. The value of the last expression in a branch becomes the verb’s result. Note J’s _5 for negative five—the underscore is the negative sign, distinct from the - verb.
Multi-way branching: select. case. end.
When you are comparing one value against several fixed alternatives, select./case. reads more cleanly than a chain of elseif.. A bare case. with no value (just case. do.) acts as the default.
Create a file named select.ijs:
| |
The argument after select. is evaluated once and compared against each case. value. The first match runs, and the trailing default case. catches everything else.
Loops: while. and for.
For genuinely sequential work—where each step depends on the result of the last—J offers while. and for. loops. Inside an explicit definition, =. makes a local assignment, which is what you want for loop counters and accumulators.
Create a file named loops.ijs:
| |
The for_i. form binds each element of i. y (the integers 0 through y-1) to the loop variable i. The continue. word skips the rest of the current iteration—here we skip odd numbers, since 2 | i is the remainder of i divided by 2. J also provides break. to exit a loop early and return. to leave the verb entirely.
The array-oriented and tacit way
Here is the part that makes J different. The factorial, the sum, and the filter above can all be written without any loop or conditional at all, because J’s verbs already operate over whole arrays.
Create a file named array_control.ijs:
| |
A few things are happening here:
+/ i. 10inserts+between the elements of0 1 2 ... 9, summing them—this replaces aforloop with an accumulator.! 5is the factorial verb; the loop inloops.ijswas reproducing a built-in.(#~ 0 = 2&|)is a tacit filter:2&|gives each element mod 2,0 = ...marks the even ones, and#~keeps exactly those—the array equivalent of “loop andif.”@.(Agenda) is J’s tacit conditional. It selects one verb from a list based on an index. The selector1 + *turns a number’s sign (_1,0,1) into an index (0,1,2) that picks the matching word.
The lesson is not that loops are forbidden—it’s that in J, “iterate over an array” is usually a property of the verb, not something you spell out. Reach for explicit control flow when the logic is truly sequential or stateful; reach for array operations and @. for everything else.
Running with Docker
Run each example with the official J image. The container’s entrypoint executes the .ijs file you pass it.
| |
Expected Output
conditionals.ijs:
negative
zero
positive
select.ijs:
one
two
three
many
loops.ijs:
120
20
array_control.ijs:
45
120
0 2 4 6 8
negative
zero
positive
Key Concepts
- Control words end in a period:
if. do. elseif. do. else. end.,select. case. do. end.,while. do. end., andfor_i. do. end.are J’s structured control keywords. - Conditionals live in explicit definitions: control structures run inside a verb defined with
3 : 0(orverb define), whereyis the argument and=.makes local assignments. select./case.for multi-way branching: cleaner than chainedelseif., with a barecase. do.serving as the default branch.continue.,break., andreturn.give fine-grained loop and verb control when you need it.- Array operations replace loops: verbs like
+/(sum),!(factorial), and#~(filter) act on whole arrays, so most “loops” in J are a single expression. @.(Agenda) is the tacit conditional: it selects a verb by index, letting you branch without naming arguments or writingif..- Think in arrays first: in J, reserve explicit loops for genuinely sequential, stateful logic; prefer array operations and tacit conditionals for everything else.
Running Today
All examples can be run using Docker:
docker pull nesachirou/jlang:latest
Comments
Loading comments...
Leave a Comment