The Flabbergast Programming Language
Flabbergast is a object-oriented macro system that uses contextual lookup (dynamic scope) and inheritance to making writing complex configurations easy.
In most languages, afterthoughts are not appreciated. However, most configurations are nothing but afterthoughts and exceptions. “I want the test version of the webserver to be the same as the production except for the database connection.” “I want the videos SMB share to be the same as the documents SMB share with a few extra users.” Flabbergast is built to service “except”, “and”, and “but”.
There is nothing so unutterably stupid that people won't waste their time on it. – Mark Rendle, The Worst Programming Language Ever. This was not explicitly about Flabbergast.
The manual describes the syntax is broad strokes and a more prosaic explanation of how it works with examples. It also describes philosophy, design patterns, and libraries. It's worth looking at some of the examples. If you want more whimsical examples, look at the Rosetta Code solutions.
For programming language geeks, the language spec describes the syntax and behaviour with formal semantics (or, at least, a poorly-written attempt at formal semantics). This is provided as a manual page such that it is included with the installed packages.
If interested in compiler hacking, the language can be compiled to a virtual machine simpler to implement than the full language spec and a self-hosting compiler is provided. The VM is documented in the KWS VM document, which does not include formal semantics because they are largely implied by the language spec.
For Ubuntu and Debian systems, Flabbergast can be easily installed by:
apt-add-repository ppa:flabbergast/ppa && apt-get update && apt-get install flabbergast-java flabbergast-cil
MacOS X packages are available on the releases page.
There are two editions of the language: one which uses the Java Virtual Machine (
flabbergast-java) and one which uses the Common Language Infrastructure (
flabbergast-cil). You need only install one. You can then get started by running
flabbergast to process a file or
flabbergast-repl to start an interactive session. If you want to run a specific edition when both are installed, use
nflabbergast for the JVM and CLI versions, respectively. The MacOS packages include only the Java edition.
For efficiency, Flabbergast allows pre-compilation of libraries. This can be done using
update-flabbergast. It can only update directories writable by the user; but it is automatically trigged upon installation of new packages containing Flabbergast code. You may wish to keep a set of your own libraries in
~/.local/share/flabbergast/lib, and it will manage those too.
Maven users can get the Java edition from The Central Repository. The dependencies are:
or you can download the JARs alone using:
mvn -DgroupId=com.github.apmasell.flabbergast -DartifactId=flabbergst-stdlib -Dversion=$VERSION dependency:get mvn -DgroupId=com.github.apmasell.flabbergast -DartifactId=flabbergast-compiler -Dversion=$VERSION dependency:get
$VESRION as appropriate. To run it, invoke Java on the JARs and run
flabbergast.MainPrinter to run the default interface, which simply runs the provided script and dumps the output, or
flabbergast.MainREPL to access the interactive debugger.
NuGet users can install the CLI edition from NuGET. You can install the package at the package management console using:
or from the command line using:
nuget install flabbergast
To build Flabbergast, you will need to have an existing copy of Flabbergast or obtain the generated compiler sources directly. You will need GNU AutoTools, Flabbergast, Make, rsync, and the preqrequistes to build one of either the JVM edition or the CLI edition. For the JVM edition, you will need the JVM 1.7 or later, ObjectWeb ASM, JLine, Commons CLI, Joda Time, and Android JSON. If you are building the CLI edition, you will need either Mono or the Common Language Runtime, the C# compiler, and either MSBuild or XBuild.
To install all these packages on Ubuntu/Debian, do:
sudo apt-get install java7-jdk autotools-dev libasm4-java libjline-java libcommons-cli-java libjoda-time-java libandroid-json-org-java mono-xbuild mono-mcs rsync
To build the compiler, if Flabbergast is installed, run the bootstrap step:
If it is not available, download the matching bootstrap package from the Internet using:
Then perform a normal AutoTools install:
./configure && make && sudo make install
There are two implementations of Flabbergast. The self-hosting version targets the JVM and the CLR.
The self-hosting compiler is rather strange, as it is not really self-hosting. The self-hosting compiler is actually a Flabbergast program that, with added syntax templates, generates a compiler for a Flabbergast compiler in a target programming language. This generated compiler reduces Flabbergast syntax to KWS VM bytecode, which are then reduced to the native VM's bytecode. This is conceptually easier to understand and allows more code re-use.
Each platform also contains an implementation of the runtime library and non-portable pieces of each library.
Flabbergast's mission is to provide a language and libraries to create configuration files for many different software applications from composable pieces that minimises the plumbing and stamp coupling while doing as much logic and validation as possible to ensure correct configuration before deployment.
Patches are welcome and patches are preferred to whining. For details, see Conduct unbecoming of a hacker. In general, the rules are as follows:
- It is very important that the language stays in a small sandbox. Free roaming of the host system or the Internet is not permitted.
- Changes to the compiler or runtime that are invisible to user are welcome. Bonus points if you apply an improvement to multiple platforms.
- Changes to the libraries are welcome with two conditions: names are
lower_snake_caseand if the interface of a platform-dependent library is changed, the other implementations get updated, even if they are stubs that throw “not implemented” errors.
- Every change to the language itself is a tattoo. We must be conservative and sure that we aren't getting a face tattoo we will regret later. Expect slow and cautious. Many things deserve to be put in the
Xexperimental keyword name space until a community process gives feedback.
The Flabbergast language would not be possible without the help of Kyle and Jonathan.
The logo is the worst symbolic representation of contextual lookup, previously called inside-out lookup.
At every point, I made design decisions that were what I thought are the “best”. Some of them are going to seem wrong to you; some of them are going to seem wrong to me. I will happily tell you the reason or goal for a decision, but I will never defend it. Experience always changes our views on things, but one cannot regret decisions where one's past self failed to be clairvoyant–that is unrealistic. Even if a feature achieves its goal, you might disagree with the goal. My goals, in no particular order, are:
- Do not be truthy.
- Use words for complicated or unusual operations in preference to symbols. The symbols we have so far are mathematics and logical operators, string join, null coalescence, and the attribute definitions.
- Fail in the most helpful way possible (i.e., fail as early and explicitly as possible).
- Avoid magic names. Current, there are
value, and the ones generated automatically in lists. I am strongly opposed to users knowing about the one in lists; in future, they might be randomised on startup.
- Avoid strings as messengers for structured data. This is part of the reason for lacking an evaluation operator.
- Do not dictate policy to the user. For instance, the predecessor to Flabbergast had a frame merge operator and it had control over how conflicting attributes were merged. The fricassée expressions give that control to the user. This is also why schema validation is unlikely; it will always be a subset of what the user really needs. This serves the “do not be truthy” goal.
- Efficiency is not as important as creating comprehensible, uniform code. Flabbergast programs should never be on a serving path, so having them be very efficient is not critical. In making decisions, doing something that uses the existing nature of the language is preferable to doing it efficiently. Efficiency is something that the compiler can worry about, not something use user should.
- Don't circumvent lookup. The lookup semantics are complicated, but powerful. Use them whenever possible, and avoid creating new semantics. Once the user has learnt them, they should never have to learn new ones, or make the mode switch to new lookup semantics.
- Don't circumvent overriding. Again, the override and definition semantics are complicated. A user should not have to switch through multiple modes of override semantics.
You may be interested in Jsonnet, which is inspired by the same forces, but takes design decisions in very different ways.