One of the goals I have for this VM project is to build actual commercial applications on top of it. Towards that end, assembler programming will not cut it. Since the VM will have memory mapped I/O for video, audio, storage, networking, input devices, and GPIO, building applications won't be terribly difficult in the virtual environment. Each of these virtual devices will mirror the behavior of dedicated circuitry in the production applications. Reading signals on a wire, having an oscillator drive a timer, and pushing out PCM and rasterizer images are all fairly well proven technologies in their own right. The issues then lie in being able to program efficiently enough that the effort to build an application is not outside the reach of an individual.
Most systems have an explicit notions about layers of languages. Low level languages are used for system programming. High level languages are used for application programming. Scripting languages are used to integrate applications. Domain Specific Languages are used to solve classes of problems too complex for the mere aggregation of applications. All of these layers are the product of generations of clever programmers seeking to abstract away the underlying reality that it is all just voltage fluctuations and the flow of electrons across heavy metal doped semiconductors. And it is this disconnection from reality that colors how the solutions create more problems, while the fundamentals remain largely ignored. How the hardware implements it's abstract machine is the reality. With this in mind, my goal when programming the system is to avoid separation from the hardware, with abstraction for abstraction's sake. Nor do I want to obscure or hide details from the programmer, as I am designing the details in their entirety. I also have no desire to prevent myself from doing anything; no matter how stupid in hindsight it may become. I want the language I use to reflect my will, and not to constrain me beyond the constraints placed upon me may my hardware design. And since I can change the design of the VM, any constraints should be removable.
So what does this mean for the language, whose name is Firth in its many incarnations:
- should preserve the design of the hardware, not abstract it away or hide the structures and processes
- must not impose levels of abstraction, but meta programming should be possible and natural
- should allow one to tailor the language to the problem, without leaving the original domain
- should use a flexible syntax and grammar that allows for user defined idioms or special forms
- must refer to objects in the concrete, not abstract types or classes
These rules form a philosophy of language design that is largely out of favor among computer scientists. The reasons for this are mostly cultural, based more on the political realities of academic life and large research institutions. Much of the focus of language designers for the past 50 years has fallen into the following traps:
- safety - making it easier for less than average programmers to contribute without doing harm
- portability - making it easier for average programmers to ignore nature of their hardware
- provability - making it easier for computer scientists to reason about the correctness of a program
- speed - making it easier to market a new technology
- parallelism - making it easier for programmers to avoid understanding state machines
Basically, the history of programming language design can be summarized as a process of trying to have smart guys make armies of less smart guys useful to large corporations in which political battles are won by middle managers managing the largest budgets, and the academics who must pump out paper after paper each year without having the time to test their theories or ground them in reality (which is both time consuming and prone to failure). This produces a perfect storm of mutually agreeable mediocrity. This is why Haskell's great innovation is the IO monad, a hack that allows its type system to do what every other language has done since the first assembler. This is why Java's run anywhere claims means you will run it on an x86 or ARM processor, but not on your micro controller (forget your custom ASIC). This is why Rubists think that a function call with an implicit dictionary parameter is Object Oriented programming. This is why Erlang is Prolog with message passing. This is why Squeak is running the same Smalltalk image bits unchanged since they burned the disk packs. This is not to say that some people like Alan Kay and some others like Chuck Moore aren't trying in doing something new; but both are in their 70s, and were there when the modern idioms were coined.
So what if we say fuck safety and built our tools like the Hole Hawgs, beastly things that did what you told them?
So what if we say fuck portability and code for the specific hardware, custom tailored to fit perfectly?
So what if we say fuck provability and rather than focusing on theoretical behavior empirically verified each design decision against real world metrics?
So what if we say fuck speed and rather than optimize our programs for performance by adding complexity, we recognized that Moore's Law is not inevitable, and simplify even at the cost of speed?
So what if we say fuck parallelism and rather than despair at Amdahl's Law, embrace concurrency and non-determinism?
Well at this point, we might as well through out standards bodies, design by committee, and popular programming methodologies that exist only to deal with the human side effects brought about by 50 years of cultural baggage. So how do we acculturate ourselves to be able to conceive of this horror of the programming world? The first step is to step back and define desirable qualities in a human language:
- Words with grammar
- Subject predicate syntax
- Idioms and shorthand
Beyond this, we really don't need much more. We need grammar to help distinguish between parts of speech. For our language we can choose how to draw distinctions. For my purposes in Firth the grammar rules are simple:
- Words which start with a capital letter are Things
- Words which start with a lower case letter are actions
- Words are separated by white space and punctuation
- Numbers are treated as being capitalized (eg. things)
- Nonalphanumeric characters are treated as being lower case (eg. verbs)
For syntax and punctuation, we're going to make it easy too:
- Subjects come before verbs, so all actions apply to the context of the last thing mentioned.
- A subject may be followed by zero or more verbs, a subject may become the object of another verb through prior reference only.
- Punctuation may add or remove layers of context.
As for idioms and shorthands:
- Any sequence of characters is a valid program, but not all sequences of character do anything productive.
- Nonalphanumeric character sequences are used to provide short hands for common idioms baked into the design of the hardware, ie. fundamental operations on numbers and memory.
- Punctuation provides the basis for program flow control and directly translates to machine instructions which modify the behavior of a word.