Mon, 10 Mar 2025 10:38:33 -0500The Do Programming Language (DRAFT)

mr's Preposter.us Blog

This is the seventh draft of the specification for a new programming language.  It is written in past-tense so I don't have to go back and change the tense once it begins to actually exist.  This page will be updated as the language evolves.

Do (pronouced "doe", like the first note in a scale) is an interpretted programming language designed to be accessible enough for new programmers and powerful enough to build personal computer applications.  In addition to this, Do aims to be self-contained, inspired by #!/this/should/be/all/i/need and Go.  To acheive this, Do includes the following tools built-in:

* REPL / editor
* Testing
* Benchmarking
* Linting
* Dictionary (“package”) management

Do's syntax is designed to be human-readable and is inspired by Markdown (in fact, a Do program is parsable by Markdown for display).  This allows Do to be self-documenting.

Do eschews symbols for descriptive words aiding in its composability and readability by humans.  Writing Do is more like talking to a human than talking to a computer.

Instead of 
for(int i =0;i++;i<10){
  printf(“Hello”);
}

The same code in Do is:
do this 10 times
1. say Hello

…or for a conditional loop:
do this until finished
1. say Hello
2. say Goodbye
3. set finished to yes

Do's flow control is based on lists, and these lists are structured the same as Markdown lists.  Lists can be embedded just like a Markdown list, and can loop conditionally or non-conditionally.

Do's primary data structure is a table, inspired by both Lua and Markdown.  By making the fundamental datatype plural, code need not handle single and multiple values differently and eliminates the need for a type system.

As shown above, words take the place of functions in Do and are collected into dictionaries (inspired by Forth).  Each dictionary is contained in a single file.  Loading a dictionary is no different from loading any other type of file other than executing it once it has been loaded.  Once loaded, the words of the dictionary become part of the language, and over time popular words will get incorporated into the default dictionary.

Long dependency chains are a source of errors, vulnerabilities and other difficulties (i.e. dependency hell).  In general, the words in a dictionary should be self-contained (depending only on core Do constructs), and not depend on words in other dictionaries.  

Do's linter makes long dependency chains visible by counting and displaying dependency depth in terms of degrees.  A first degree dependency occurs when a program depends a dictionary (almost all programs have a first degree dependency).  A second degree dependency occurs when a word in a dictionary depends on word in another dictionary.  The linter will flag this and issue a warning.  A third-degree dependency occurs when an additional dictionary is added to the chain.  The linter will flag this as well and consider it an error.  

The interpreter will run programs with second degree or greater dependencies, but it will complain a lot, and these complaints will be written into the dictionary of the offending word.

Tests are required (the interpreter will throw an error if no tests are present).  Minimally all dictionaries have at least one self-test that exercises all words so any dictionary can be executed stand-alone to verify its integrity.

Errors are handled at the dictionary level, they do not “bubble up” to the caller.  Words that throw unhandled errors at runtime have their dictionary entires modified by the interpreter to add a record of the error to the dictionary source itself as a reminder and aid to the programmer to improve error handling.

Do's REPL can load and run Do programs and interactively execute any Do word, so it is suitable for use as a shell as well as a programming environment.  Interacting with the REPL can be conversational, similar to a text adventure.  Writing (and potentially, using) a Do program is more like working with another person than a machine.

Workshop
There are some things we are considering for Do that are even more noncommittal than the draft specification.  Those things live below this line until they are mature enough to go into the spec. or disappear.

If Do includes a “compiler” (something that turns source code into a single distributed artifact), it must be capable of extracting the identical source from the artifact (i.e. the compilation process must be lossless).