SORTA
SORTA is the two-stack scripting language implemented by Daniel J. Bernstein's 1,542-byte C program that won Best of Show at the 8th International Obfuscated C Code Contest in 1991 - a language with features, in its author's words, "sorta from C, sorta from FORTH, and sorta from Ada", with one stack for integers, one for strings, single-character named programs, real Unix fork/exec/pipe primitives and infinite-depth tail recursion. The 2005 date attached to it in derived language lists is the day a 99 Bottles of Beer program was submitted in it, not the year the language appeared
Created by Daniel J. Bernstein (djb), who designed the language and wrote its only interpreter as his IOCCC entry. He is far better known for later work - qmail, djbdns, Curve25519 and the free-speech case Bernstein v. United States - and SORTA is his single IOCCC win: the contest's author record lists exactly one winning entry for him, 1991_brnstnd
SORTA is a small stack-based scripting language whose entire implementation is a 1,542-byte C program. Daniel J. Bernstein wrote it for the 8th International Obfuscated C Code Contest in 1991, where rule 1 capped a complete entry at 1,536 bytes of source, and the judges gave it Best of Show. (The archived original is a few bytes over that cap; the archive does not say why, and the most likely explanation is the reconstruction from the contest’s line-split mail submission format.) The name is a joke about its parentage, explained in the first sentence of the author’s remarks: SORTA is “a systems and numerical programming language with features sorta from C, sorta from FORTH, and sorta from Ada.”
Each of the three is a real, identifiable component. From C come the file and process primitives - open, close, dup, fork, execvp, pipe, wait, all exposed as single characters - and, the author notes drily, “absolutely brilliant error messages like ‘?’”. From FORTH comes the execution model: a program is a stream of characters read from standard input, each character an operation on a stack, with no syntax to speak of. From Ada comes the claim that “all SORTA operations are strongly typed, detect practically any failure, and garbage-collect” - which in practice means two separate stacks, one holding integers and one holding heap-allocated strings of unlimited length, so that a string operation can never be handed an integer, and no operation can crash the interpreter. Bernstein’s own summary of that last property is characteristically flat: “I don’t think it’s possible to crash the interpreter.”
Two things should be said plainly at the outset, because the catalogue entry that brings most readers to this page gets both wrong. SORTA is from 1991, not 2005; the 2005 date is the day a French hobbyist named Laurent Vogel posted a 99 Bottles of Beer program written in SORTA to a website that collects such things. And SORTA is not a functional language. It is about as imperative as a language can be: a sequence of single-character effects on two mutable stacks, with the only control flow being “if the top of the integer stack is non-zero, run the program filed under this character.”
History and Origins
The 8th IOCCC
The International Obfuscated C Code Contest, run by Landon Curt Noll and Larry Bassel, had by 1991 settled into its familiar shape: a hard size limit, a handful of named awards, and judging done on sources stripped of their authors’ names. The 1991 rules dedicated the contest “to the ANSI C pre-processor” and set rule 1 at 1,536 bytes for a complete program. Entries were mailed to [email protected], or via UUCP to ...!{sun,pacbell,uunet,pyramid}!hoptoad!judges.
That year the judges declined to name a single winner. “This year, we did not single out an entry that was better than all of the rest,” their notes read. “We selected 3 entries that, in our opinion, went beyond all of the other entries this year”: Brian Westley’s Grand Prize, Diomidis Spinellis’s Most Well Rounded, and Bernstein’s Best of Show. Nine entries won in all.
Bernstein was nineteen when the contest ran - entries were accepted from March 1991 and winners posted that June, and he turned twenty the following October - and he took his BA in mathematics from New York University the same year. The software that made him widely known was still years off: qmail arrived in 1996, ezmlm and daemontools in 1997, djbdns at the end of the decade, and the litigation over export controls on cryptographic source code that carries his name was filed in 1995. The IOCCC’s author record shows SORTA is his only winning entry.
The bid for “most useful program”, and its rejection
The entry’s single string constant is a plea to the judges, hidden in plain sight as the pool of characters the interpreter uses to recognise commands:
| |
The judges’ remarks record what happened: “The author wished to win the ‘most useful program’ award and documented this in the source code. The judges were unmoved by this blatant attempt to influence the contest and rejected this idea… so we gave it the ‘Best of Show’ instead!!”
The string is not decoration. It is the command table. Every command in the language is written in the source as an index into I: the macro #define J(x,y) F(I[x],y) means “if the current character is I[x], do y”, so that the division operator appears in the source as J(38,...) because I[38] is /, the concatenation operator as J(54,...) because I[54] is T, and so on across some thirty commands. Bernstein’s own assessment of the trick, from his remarks: “The character pool (I after cpp) makes it rather painful to see the effect of commands at a glance. I can just imagine people spending hours bouncing between the pool and the rest of the code, or accidentally changing the pool without realizing its importance.” The same string, offset by 73 characters, is the ? that the interpreter prints after echoing any character it does not recognise.
An obfuscator’s notes on his own work
The remarks are unusually candid about which parts of the obfuscation the author rated. He liked the touches that read as ordinary engineering care until you check them - “Observe, for instance, how i and s are the string and integer stacks respectively” (they are named for the other stack’s contents) - and the way unbalanced macro braces mislead the eye in fragments like if(c>0){y+1]=z[c];. He rated the rest as routine: “This is pretty standard obfuscation otherwise.”
He also thought the language did obfuscation work that the C could not: “the SORTA language itself encourages you to write not merely obfuscated but plain incomprehensible scripts (like the examples in sorta.README) - after working with the language for a while, I guess I can read it pretty easily, but I also think FORTH is a beautiful language.” And he listed what he had wanted to add and could not fit: “string extraction and matching, reading from files into strings, and encrypting the string pool to further confuse the judges. I don’t think I can fit this into the size limit, unfortunately.”
Afterwards
Nothing further happened to the language. Bernstein never returned to it. The Esolang wiki noticed it in 2006, when the editor Oerjan added a two-sentence stub - “SORTA is a language by Daniel J. Bernstein. His interpreter won Best of Show in the 1991 International Obfuscated C Code Contest”. The article has been edited exactly twice since: in February 2019 B jonas filed it under Languages, Before 1993, Stack-based and Implemented and refreshed the link to the IOCCC page, and in May 2022 PythonshellDebugwindow updated that link again. The two sentences of prose have never changed.
The one piece of outside use came on 20 April 2005, when Laurent Vogel submitted a 99 Bottles of Beer program in SORTA to 99-bottles-of-beer.net, becoming entry 604 there. Vogel’s site, lvogel.free.fr, carried a similar sort of thing across the early 2000s - Thue interpreters, programs in qpliu’s nouse, a small POSIX sed - and the beer program is written with evident fluency in a language he can only have learned from the IOCCC README. That submission is the reason SORTA appears in derived language lists at all, and the reason it appears there dated 2005.
Design Philosophy
Two stacks, no variables
SORTA has an integer stack and a string stack and nothing else that a program can name. There are no variables, no arrays, no records; the closest thing to storage is the ability to keep values on a stack and reach past the top of it. Reaching past the top is what the two swap commands are for: s pops n from the integer stack and swaps the top with the (n+1)th element down, so 1s swaps the top two, 2s swaps the top with the third down; S is the same operation on the string stack, taking its count from the integer stack.
That single primitive is doing the work that local variables do in other languages, and the shipped example scripts document their stack effects in comments the way FORTH programmers do:
[D2sD3s]:Dld [ input m n, output m n m n ]ld
[D2s1s_+1s]:-ld [ input m n, output m-n n ]ld
The separation of the stacks is the “strong typing” the author claims. A command works on one stack or the other, never on “the stack”, so + cannot be handed a string and T (concatenate) cannot be handed an integer. Where other minimal languages achieve safety by tagging values, SORTA achieves it by segregating them, which costs nothing at runtime and nothing in code size.
Programs are characters
The high-level layer of the language is two commands. :x copies the top of the string stack into “a program labeled by character x”; =x pops the integer stack and, if the value was non-zero, executes that program. There are 256 possible program names, one per character, and that is the entire named-abstraction facility - no parameters, no return values, no scoping. Recursion is unbounded only when it is in tail position; a program that recurses without doing so runs the interpreter past its buffered-command limit and exits silently with status 2, which a 400-deep non-tail recursion does on a current build.
Everything else is idiom, and the README lists the idioms explicitly because there is no other way to learn them:
| To do this | Write |
|---|---|
| drop the top of the string stack | ld |
call program x unconditionally | 1=x |
| subtract | _+ |
compare with < | 1s> |
| print the top of the integer stack | # |
| write a comment | [ ... ]ld |
The comment idiom is the neatest of these: [...] pushes its contents onto the string stack as a literal, and ld immediately throws it away. A comment in SORTA is a string you allocate and discard.
Because a program is just a string, and a string can be built at runtime, SORTA can construct and run code on the fly. The iio example does exactly that, storing the literal "2 2+" under program name x and then invoking it:
[ a simple example of interpreting code on the fly ]ld
["] "2 2+":xT ["]T " produces "T 1=x#T " which should be 4."T`
which prints "2 2+" produces 4 which should be 4. The icalc example uses the same mechanism for something genuinely necessary: SORTA has no primitive that converts a string to a number, so icalc turns its command-line arguments into integers by storing them as a program and executing them, letting the interpreter’s own numeric literal handling do the parsing.
One conditional, and tail calls that do not grow
There is no loop construct and no unconditional jump. Iteration is a program that calls itself, guarded by =. The saving grace is that the interpreter does not build a call stack for the last call in a program: the entry ships a script, itailrec, whose only stated purpose is “to prove that sorta can do infinite tail recursion.” It is twenty-two bytes long:
[3*#" "T$ldD=f]:f
1=f
and runs until you stop it, printing 3, 9, 27, 81 and onward - “the powers of 3 (mod your computer’s word size)”, as the README puts it. On a modern 64-bit build the sequence turns negative just past 1,162,261,467, because the arithmetic is the host C int.
Failure is silence
SORTA’s error behaviour is deliberate and is the one place where the joke and the design coincide. Operations on a stack that is too short “are silently ignored”, with three documented exceptions. Unrecognised commands are echoed followed by ? - type Z at the interpreter and it answers Z?. If any stack grows past the compile-time limit o (250 by default, and the README warns “you should not make o larger than 250”), the interpreter exits silently with status 2. There is no other diagnostic, anywhere.
The Language
The command set below is the author’s, grouped as he grouped it. Digits accumulate into an integer literal; anything that is not a digit terminates one; spaces and newlines are ignored except as separators.
Basic operations
| Command | Effect |
|---|---|
q | quit |
| number | push onto the integer stack |
"..." or [...] | push a string of unlimited length onto the string stack |
# | render the top integer as text, non-destructively, and push it onto the string stack |
` / $ | print the top string non-destructively, with / without a newline |
d / D | drop / duplicate the top integer |
' | duplicate the top string |
s / S | pop n, swap the top of the integer / string stack with the (n+1)th element down |
l | pop a string, push its length |
a / A | push argc / pop i and push argv[i] |
T | concatenate the top two strings |
_ + * / > & | negate, add, multiply, divide, C-style greater-than, and bitwise NAND |
& is NAND and there is nothing else: the README points out that NAND alone suffices, and icalc builds NOT, AND, OR and XOR out of it.
System operations
o performs open(s1, i2, i1), O closes a descriptor, u duplicates one with dup, F forks, P creates a pipe and pushes both ends, w waits for a child, and ! execs the program named by the top of the string stack, taking its arguments from the strings below it in reverse order with the first character of each lopped off and an empty string marking the end of the list. The author flags the one real hazard: F “is not always safe while SORTA is reading keyboard input or a script, as the forked programs share file descriptors. It is always safe inside a program.”
High-level operations
:x stores the top string as program x; =x pops an integer and runs program x if it was non-zero. The README notes one syntactic trap worth repeating: “a digit at the end of a program will merge with any digits after =x; in that case you usually want to add a space at the end of the program.”
99 Bottles of Beer
Laurent Vogel’s 2005 program is the best single demonstration of what the language reads like in the hands of someone who has learned it:
[ sorta version of 99 bottles of beer ]ld
[ Laurent Vogel, http://lvogel.free.fr ]ld
[" bottle"TD1_+=s" of beer"T$ld`ldD]:p[" on the wall"1STD]:w[""`ldD=a]:n
[","=w#=p"."#=p"Take one down, pass it around,"`ldd1_+DD"."=w#=p=n]:a99D
["s"T]:sD=a"."2D=w"No more"=p
Four programs are defined - p prints a count and the words “bottle(s) of beer”, w appends " on the wall", s appends the plural “s”, a is one verse and calls itself - and 99D starts it. The plural is handled arithmetically rather than by a comparison: D1_+=s duplicates the count, computes n−1, and uses that as the condition for calling s, so the “s” is appended for every count except one. It prints the full song, 494 lines, ending correctly with “No more bottles of beer on the wall.”
Running SORTA
The interpreter is in the IOCCC archive, under 1991/brnstnd. It builds and runs today; the following was done on macOS on 6 September 2026.
| |
which prints:
7 in binary is 111
42 in binary is 101010
42 + 7 is 49
42 - 7 is 35
42 * 7 is 294
42 / 7 is 6
42 % 7 is 0
~ 42 is -43 (-101011)
42 & 7 is 2 (10)
42 | 7 is 47 (101111)
42 ^ 7 is 45 (101101)
The supplied try.sh walks through every shipped example except the endless itailrec, including the sleep-and-wait script and the who | sort pipeline; the entry README suggests running itailrec separately. A few notes on getting it to build:
- The IOCCC’s Makefile compiles with
-std=gnu90and a long list of warning suppressions, and defines-DM=malloc -DX=free -Do=250. Theoparameter is the stack depth limit; the README says not to raise it above 250. - The compiled file
brnstnd.cdiffers from the submittedbrnstnd.orig.cin exactly one documented way:#Dhas been expanded to#define. The original relied on#define D definefollowed by#D ..., which is not legal ANSI C - the 1991 judges wrote that “a number of entries made use of” it, that they would not reject 1991 entries over it since the rules had not forbidden it, and that they did not want future entries to do so. - Because the entry does not declare
malloc, some compilers warn about pointer conversions. The author warned about this in 1991 and the warnings are suppressed in the modern Makefile. - SORTA “wants
fork(),execvp(),open(),close(),dup(),pipe(), andwait(), so it obviously won’t even compile on a non-UNIX machine.” That was written in 1991 and remains the accurate statement of portability: any Unix-like system with those calls. It assumes a 256-character character set and that'0'through'9'are contiguous, but the author is explicit that it “does not depend on ASCII, despite the code appearance.”
Evolution
There is none, and that is the point. SORTA was complete when it was submitted, has never had a second version or a second implementation, and acquired exactly two things after 1991: a wiki stub in 2006 and a 99 Bottles of Beer program in 2005. Its only ongoing maintenance is the IOCCC’s, which in the 2024-2025 rebuild of the archive gave the entry a Makefile, a demonstration script and a JSON manifest so that it would keep compiling - the same curatorial care given to every winner, and the reason a 1991 contest program still runs on a 2026 laptop without editing a line of it.
Current Relevance
SORTA has no users, no community and no successors. Its interest now is of three kinds.
The first is as a demonstration of how much language fits in 1.5 KB of C. Two typed stacks with garbage-collected unbounded strings, thirty-odd operations, first-class named programs, runtime code construction, proper tail calls, and a working Unix process and file-descriptor interface, with no crash reachable from any input - written under a hard size cap, as a joke, in 1991. That is a real result about the cost of language features, delivered in the least serious possible venue.
The second is biographical. Bernstein’s later reputation rests on programs that are small, fast, unusually careful about failure modes and famously opinionated about interfaces. SORTA, written at nineteen, already has the shape: the stack discipline that makes type errors unrepresentable, the exhaustive account of what happens when each operation fails, the flat refusal to add anything that will not fit. That the deliberately unreadable joke program and the security software share a design temperament is the most interesting thing about the entry.
The third is cautionary, and is the reason this page spends space on dates. SORTA appears in circulating language lists as a 2005 functional esoteric language. Every part of that except “esoteric” is wrong, and the error is traceable: someone scraped a catalogue of 99 Bottles of Beer programs, took the submission date of the program for the birth date of the language, and guessed at a paradigm from the look of the code. The primary source - a contest entry, its README and its example scripts, all of it still online and still executable - has been unambiguous for thirty-five years.
Why It Matters
The IOCCC’s premise is that you learn something about a language by watching people abuse it, and the 1991 Best of Show is the strongest case for that premise. To hide a language inside 1,536 bytes of C, Bernstein had to make every design decision pay for itself in bytes, and the decisions he made are the ones a minimal-language designer would make if forced to justify each one: two stacks instead of a type tag, NAND instead of a bitwise suite, one conditional call instead of a control-flow vocabulary, characters instead of identifiers, silence instead of diagnostics. The result is not a good language, and was never meant to be. It is a very clear one - a working sketch of how little machinery a usable Unix scripting language actually requires, drawn by someone who would spend the rest of his career arguing that most software is far bigger than it needs to be.
Not to be confused with
- Sorta, the general-purpose word, which turns up in package and project names across GitHub with no connection to this language.
sort, the Unix utility - which SORTA’siwhosortexample execs, but is otherwise unrelated.- nouse, qpliu’s esoteric language, in which the same Laurent Vogel wrote several programs also linked from his site; the two are separate languages with separate authors.
Sources
All read on 6 September 2026.
- IOCCC, 1991/brnstnd - Best of Show - judges’ remarks, author’s remarks, and the full language reference.
- IOCCC, the SORTA README - the thirteen annotated example scripts.
- IOCCC, Winning Entries of 1991 - The 8th IOCCC and the 1991 rules - the three top awards, the
#define X definenote, and rule 1’s 1,536-byte limit. - The entry tarball
1991_brnstnd.tar.bz2, downloaded, compiled with clang and run, including its.entry.jsonmanifest; IOCCC, Winning authors and the author recordDaniel_J_Bernstein.json, whosewinning_entry_setcontains1991_brnstndand nothing else. - Esolang wiki, SORTA, and its three-revision history via the MediaWiki API.
- Internet Archive captures of
99-bottles-of-beer.net/language-sorta-604.html, 13 January 2006 through 9 November 2024, for Laurent Vogel’s program, its 20 April 2005 date and its 3.00-in-two-votes score; and oflvogel.free.fr/misc.htmfor Vogel’s other esoteric-language work.
Timeline
Notable Uses & Legacy
icalc, the entry's own showpiece
A thirty-three-line SORTA script, twenty-six lines of it non-blank, shipped with the interpreter, that takes two integers from the command line and prints their sum, difference, product, quotient, remainder, bitwise NOT, AND, OR and XOR - the two operands and the four bitwise results each accompanied by a hand-built binary rendering, since SORTA has no binary output primitive either. SORTA's only bitwise primitive is NAND (&), so icalc constructs the rest from it - the README's aside that "if you can't remember offhand that D2sD3s&2sD&1sD&&&D& means XOR, you can just look it up here" is the closest the entry comes to a standard library. It also converts its string arguments to numbers without any string-to-number primitive, by re-executing them as SORTA code
irot13 and iwhosort, the Unix plumbing demonstrations
Two scripts that exist to show the language is not a toy calculator. irot13 opens a file named on the command line, replaces descriptor 0 with it using 0Ou - so the file becomes the exec'd program's standard input, though the README describes the step as closing stdout - and execs a BSD-style tr to rotate letters by thirteen places, printing a proper diagnostic if the open fails. iwhosort builds a pipe with P, forks twice and execs who and sort to run the pipeline who | sort entirely from SORTA. The system half of the language - open, close, dup, fork, execvp, pipe, wait - is genuinely usable
itailrec, the twenty-two-byte proof
The whole script is [3*#" "T$ldD=f]:f followed by 1=f. Its stated purpose is "to prove that sorta can do infinite tail recursion": program f multiplies the top of the integer stack by three, prints it and calls itself, and because the call is the last thing it does the interpreter loops instead of nesting. It runs until interrupted, printing the powers of three modulo the host word size - on a 64-bit build the values go negative once they pass 2^31, which is the C int arithmetic showing through
99 Bottles of Beer, entry 604
Laurent Vogel's April 2005 rendition, five lines long including two comment lines, and the only SORTA program known to have been written by anyone other than Bernstein. It defines four programs - p prints a bottle count, w appends " on the wall", s pluralises, a is the recursive verse - and gets the singular/plural switch from the arithmetic: " bottle"TD1_+=s tests n-1 and appends the "s" only when it is non-zero. Run under the 1991 interpreter in 2026 it prints the full 494-line song, correctly singular at one bottle, ending "No more bottles of beer on the wall."