Sunteți pe pagina 1din 43

flabbergast/flabbergast-manual.

md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Features Business Explore Pricing This repository Search Sign in or Sign up

flabbergast-config / flabbergast Watch 8 Star 49 Fork 4

Code Issues 24 Pull requests 0 Projects 0 Pulse Graphs

Branch: master flabbergast / flabbergast-manual.md Find file Copy path

Fetching contributors

Cannot retrieve contributors at this time

!"!#$%&'()$*!!+,$)%-./$ $01$23 Raw Blame History

The Flabbergast Programming Language

Flabbergast is a rather unique programming language. It is best-described as an object-oriented macro system, though it's
best not to associate it too much with object-oriented programming. Conceptually, it is based on a proprietary programming
language used at Google for creating configurations. At Google, this language is much despised because it is difficult to
debug and has many design flaws. However, it is special in that it is a member of a unique language family. It has features
from other languages: particularly functional languages and object-oriented languages. Flabbergast aims to be the second in
that family of languages and, hopefully, be more loved by being easier to debug, easier to understand, and more semantically
sturdy.

Follow along at home with Flabbergast Fiddle!

A Worked Example: Apache Aurora

Let's start with an example for a simple job that runs on Apache Aurora. Aurora is a long-running job configuration system for
Mesos. It's purposes is to collect and dispatch all the needed job information to Mesos. In Aurora, a file consists of many jobs,
each with a task to perform. A task can have multiple processes that run inside of it. Most resources are configured on the job
level; some on the task level.

Flabbergast is going to describe the Aurora configuration using templates and frames and it will generate a big string, the
configuration file for Aurora. If you run the Flabbergast interpreter on these files, it will produce a working Aurora configuration
as output.

The first thing needed is some basic plumbing:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 1 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

456-647%&8$9$:6-;$%&894<4.=(>456-64$?$@;<-6A$A=($B56-64$%&8646CD
=E7F&%($9$456-647%&8D456-647F&%($G$?$H6(4A($4'$B56-64$.-'F&I564A&-'$F&%(
$$J-8)$9$K$L$?$B56-64$6(M5&6()$E($<6-N&O($4$%&)A$-F$J-8D$P($=4N($'-'($)-$F46D
Q
N4%5($9$=E7F&%(DN4%5($?$:%488(6I4)A$&)$I-&'I$A-$O5;<$A=&)$)A6&'I$A-$A=($-5A<5AD

This won't do anything useful, but we have a basic skeleton. Let's create a job.

456-647%&8$9$:6-;$%&894<4.=(>456-64
=E7F&%($9$456-647%&8D456-647F&%($G
$$J-8)$9$K
$$$$J-8$G$?$H6(4A($4$J-8D$R=&)$.-5%O$4%)-$8($S456-647%&8DJ-8ST$85A$E($=4N($'-A=&'I$(%)($'4;(O$SJ-8SD
$$$$$$&')A4'.()$9$!$?$U'($6(<%&.4$-F$A=&)$J-8$)=-5%O$65'D
$$$$$$J-87'4;($9$V=(%%-7E-6%OV$?$W6-N&O($4$F6&('O%C$J-8$'4;(D
$$$$$$A4)X$9$456-647%&8DA4)X$G$<6-.())()$9$KL$Q$?$Y4.=$J-8$'((O)$4$A4)XD
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

This will create one job, but this file won't work. A job needs a $.%5)A(6$ and a $6-%($; it is also desirable to specify
$6()-56.()$.

456-647%&8$9$:6-;$%&894<4.=(>456-64
.%5)A(6$9$V.%5)A(6!V
6-%($9$VJ6=4.X(6V
6()-56.()$9$G
$$.<5$9$ZD!
$$64;$9$!#[&
$$O&)X$9$!#[&
Q
=E7F&%($9$456-647%&8D456-647F&%($G
$$J-8)$9$K
$$$$J-8$G
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G$<6-.())()$9$KL$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

I chose to put $.%5)A(6$, $6-%($, and $6()-56.()$ resources at the top-level. This is so that they are shared between all jobs
that I create. It is also completely valid to do:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 2 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

456-647%&8$9$:6-;$%&894<4.=(>456-64
=E7F&%($9$456-647%&8D456-647F&%($G
$$6()-56.()$9$G
$$$$.<5$9$ZD!
$$$$64;$9$!#[&
$$$$O&)X$9$!#[&
$$Q
$$J-8)$9$K
$$$$J-8$G
$$$$$$.%5)A(6$9$V.%5)A(6!V
$$$$$$6-%($9$VJ6=4.X(6V
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G$<6-.())()$9$KL$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

I can even split the $6()-56.()$ frame.

456-647%&8$9$:6-;$%&894<4.=(>456-64
6-%($9$VJ6=4.X(6V
6()-56.()$9$G
$$.<5$9$ZD\$?$R=&)$N4%5($E&%%$8($(.%&<)(O$8C!
$$64;$9$!#[&
Q
=E7F&%($9$456-647%&8D456-647F&%($G
$$6()-56.()$9$G
$$$$O&)X$9$!#[&
$$Q
$$J-8)$9$K
$$$$J-8$G
$$$$$$6()-56.()$9$G
$$$$$$$$.<5$9$ZD!$?$!$A=&)$-'(T$8(.45)($A=&)$-'($&)$].%-)(6^$A-$A=($<-&'A$-F$5)(D
$$$$$$Q
$$$$$$.%5)A(6$9$V.%5)A(6!V
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G$<6-.())()$9$KL$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

In this case, it doesn't change the output, but it allows me to control which parameters are shared by which jobs.

Our task is pretty useless, let's give it some processes:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 3 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

456-647%&8$9$:6-;$%&894<4.=(>456-64
.%5)A(6$9$V.%5)A(6!V
6-%($9$VJ6=4.X(6V
6()-56.()$9$G
$$.<5$9$ZD!
$$64;$9$!#[&
$$O&)X$9$!#[&
Q
=E7F&%($9$456-647%&8D456-647F&%($G
$$J-8)$9$K
$$$$J-8$G
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G
$$$$$$$$<6-.())()$9$G$?$_(F&'($A=($<6-.())()$!
$$$$$$$$$$=E$9$<6-.())$G$?$!$5)&'I$<6-.())$A(;<%4A(
$$$$$$$$$$$$<6-.())7'4;($9$V=EV$?$R=($'4;($-F$A=&)$<6-.())$E&%%$8($S=ES
$$$$$$$$$$$$.-;;4'O7%&'($9$K$V(.=-$=(%%-$E-6%OV$L$?$R=($.-;;4'O$%&'($E($E4'A$A-$65'D
$$$$$$$$$$Q
$$$$$$$$Q
$$$$$$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

This will give us a basic configuration. Aurora allows multiple replicas/instances of a job. Suppose we want each replica to
know its identity:

456-647%&8$9$:6-;$%&894<4.=(>456-64
.%5)A(6$9$V.%5)A(6!V
6-%($9$VJ6=4.X(6V
6()-56.()$9$G
$$.<5$9$ZD!
$$64;$9$!#[&
$$O&)X$9$!#[&
Q
=E7F&%($9$456-647%&8D456-647F&%($G
$$J-8)$9$K
$$$$J-8$G
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G
$$$$$$$$<6-.())()$9$G
$$$$$$$$$$=E$9$<6-.())$G
$$$$$$$$$$$$<6-.())7'4;($9$V=EV
$$$$$$$$$$$$.-;;4'O7%&'($9$K$V(.=-$=(%%-$E-6%OD$@$4;$VT$.566('A7&')A4'.($L
$$$$$$$$$$Q
$$$$$$$$Q
$$$$$$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

Aurora also allows setting multiple ports for incoming connections.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 4 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

456-647%&8$9$:6-;$%&894<4.=(>456-64
.%5)A(6$9$V.%5)A(6!V
6-%($9$VJ6=4.X(6V
6()-56.()$9$G
$$.<5$9$ZD!
$$64;$9$!#[&
$$O&)X$9$!#[&
Q
=E7F&%($9$456-647%&8D456-647F&%($G
$$J-8)$9$K
$$$$J-8$G
$$$$$$&')A4'.()$9$!
$$$$$$J-87'4;($9$V=(%%-7E-6%OV
$$$$$$A4)X$9$456-647%&8DA4)X$G
$$$$$$$$<-6A7O(F)$`9$G
$$$$$$$$$$a;<<$9$b5%%$?$H6(4A&'I$4$'(E$'5%%$('A6CT$O(F&'()$4$'(E$<-6AD$3C$)(AA&'I$&A$A-$4$)A6&'IT$&A$8(.-;()$4'$4%&4)D
$$$$$$$$Q
$$$$$$$$<6-.())()$9$G
$$$$$$$$$$=E$9$<6-.())$G
$$$$$$$$$$$$<6-.())7'4;($9$V=EV
$$$$$$$$$$$$.-;;4'O7%&'($9$K$V=(%%-E-6%OO$cc=AA<$VT$<-6A)D=AA<T$V$cca;<<$VT$<-6A)Da;<<$L
$$$$$$$$$$Q
$$$$$$$$Q
$$$$$$Q
$$$$Q
$$L
Q
N4%5($9$=E7F&%(DN4%5(

What makes Flabbergast helpful is how you can extend these base templates to suit your needs. You can create a template
that runs a database. It could calculate the needed disk given a list of datasets. That way, a user gets a correctly configured
database only having to specify the data sets. Other things to consider might be creating a standard configuration for a
sharded system, then using a fricasse to create them over the right range. Or, even, combine the two: create a lists of
grouped datasets, then use those to bring up many similar databases to serve them.

Background
It is important to understand the niche for Flabbergast: it is a configuration language. The configuration of some systems is
rather trivial: $F)A48$ and $6()-%ND.-'F$ have remained virtually unchanged over many years. More complex programs, such
as Apache, BIND, Samba, and CUPS have significantly more complicated configurations. The complexity is not a function of
the configuration itself; indeed $);8D.-'F$ is just an INI file. Complexity comes because there's a desire to share common
configuration between elements (e.g., the list of privileged users among SMB shares). Configuration files start to grow
awkward macro systems, get preprocessed using M4 or the like, or get evermore specific configuration operations to migrate
the complexity into the binary.

Flabbergast, in some ways, is like a macro system. However, macro systems, such as M4 and the CPP, operate by
manipulating text or tokens and can only ever output more text or tokens. Flabbergast is a language meant to manipulate
structured configuration: frames. Frames can behave somewhat like objects: they can have inheritance relations, they can be
extended, and, finally, rendered into a standard configuration format, which might be the frames themselves or it could be
text. Either way, the needs of the configuration remain in the Flabbergast language; not the binary consuming the
configuration. Moreover, Flabbergast makes it possible to write libraries of utilities and templates for configurations.

Another way to think about that language is that it is a system where dependency injection is not something added to the
language, but is implicit. Every reference is an injection point. Defining an attribute is performing an injection. Since attributes

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 5 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

can be overridden, the injection framework remains fluid.

For more background on the complexity of configuration languages, take a look at Configuration Pinocchio, presented at
SREcon15 Europe, and the companion paper.

Quick Notes on Syntax


To make adoption easier, Flabbergast tries to be like other popular languages in the inconsequential stuff. If compared to any
mainstream language, the arithmetic operators are going to behave like normal. Flabbergast also tries to use words over
symbols. Granted, it has the provincial assumption that everyone knows English, but the goal is to avoid looking like line
noise. The unusual symbols are: $9$ for definition (like JSON), $d$ for string join, and $ee$ for null coalescence (like C#), $eD$
for the null-coalescing lookup (like CoffeeScript's existential property access), and $`9$ for overriding (a unique property of the
language).

For a quick reference, check the cheatsheet.

Getting Started
As general background, this guide assumes some previous experience programming. Familiarity with one functional
language and one object-oriented language is helpful. A deeper understanding of a dynamically-typed object-oriented
languages can be extremely helpful, though not necessary. Use of a macro processor might provide some extra insights.

Flabbergast has many of the same data types as many other languages: Booleans, integers, floating-point numbers, and
strings; which look and act much like they do in other languages. It also has two special data types: frames and templates.
Note that there are no functions (first class or otherwise); templates can do some of the work of functions. Flabbergast is pure
and declarative: everything is an expression and no expression can have indirect consequences on another expression.

Frames are similar to Perl's hashes, Python's objects, JavaScript's objects and C#'s anonymous classes. A frame is a
dictionary/map between identifiers and values, which may be of any of the aforementioned types. Frames are immutable
upon creation. Each entry in a frame is called an attribute, having a name and a value. The entire scope of a file is also one
big frame:

4$9$"
8$9$G
$$a$9$R65(
$$C$9$Vf(%%-T$P-6%OV
Q

This creates a frame (the file-level frame) that has two attributes: $4$, which is the integer 5, and $8$, which is another frame
containing two attributes: $a$, which is the Boolean true, and $C$ which is a string.

When creating a frame, an expression can appear on the right side of the $9$ to compute the value.

4$9$"
8$9$4$g$4$?$h&(%O)$\"

For integers and floating-point numbers, the usual mathematical and comparison operators are provided. There are also a
few special operators for floating-point numbers ($@)$:&'&A($ and $@)$b4b$) and some special constants ($@'F&'&AC$ and
$b4b$). There are also some limit constants: $@'A[4a$, $@'A[&'$, $:%-4A[4a$, and $:%-4A[&'$.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 6 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

4$9$"DZ
8$9$@'F&'&AC
.$9$4$@)$:&'&A($?$h&(%O)$R65(
O$9$8$@)$:&'&A($?$h&(%O)$:4%)(
.$9$4$g$8$?$h&(%O)$@'F&'&AC
($9$8$g$Z$?$h&(%O)$b4b
F$9$!Z$>$+$?$h&(%O)$+$*!Z$4'O$+$46($&'A(I(6)/
I$9$!ZDZ$>$+$?$h&(%O)$+D++++++$*+$&)$5<I64O(O/
=$9$!Z$i$"$?$h&(%O)$:4%)(
&$9$!DZ$jk$c+$?$h&(%O)$R65(

Integers also have a few special suffixes for dealing with large values, including time. The suffixes $l$, $[$, and $X$ are giga-,
mega- and kilo-, respectively. These are the SI versions (powers of 1000). There are also the computer versions, $l&$, $[&$
and $X&$, which are powers of 1024. For time durations, there are the suffixes $O$, $=$, $;$, and $)$, which express to days,
hours, minutes, and seconds, respectively, in seconds.

4$9$mX&$?$h&(%O)$mZ0#
8$9$"l$?$h&(%O)$"ZZZ"ZZZ"ZZZ
.$9$!=\;")$?$h&(%O)$+,\"

Integers also have bit-wise operators $3d$ (and), $3n$ (or), $3o$ (xor), and $3p$ (complement).

Booleans are very much as expected, with $p$ for logical negation, $dd$ for short-circuiting conjunction, and $nn$ for short-
circuiting disjunction. The comparison operators also work; one quirk is that they all work, not only equal and not equal. This
means that truth is greater than falsehooddon't read too much into it.

4$9$R65($dd$:4%)($?$h&(%O)$:4%)(
8$9$:4%)($dd$Y66-6$V@$O-'qA$.46(V$?$h&(%O)$:4%)(
.$9$R65($pk$:4%)($?$h&(%O)$R65(T$A=&)$&)$rUs
O$9$R65($j$:4%)($?$h&(%O)$R65(

Strings support the usual C-style escape sequences, and Unicode escape sequences. They are also implicitly multi-line, like
in shell. There is a special escape sequence $t*/$ which allows embedding an expression inside a string. Strings can also be
joined using $d$. Comparison works lexicographically on the strings.

4$9$Vu&'I%(c%&'($)A6&'IDV
8$9$V[5%A&
%&'(
)A6&'IDV
.$9$V+$g$m$k$t*+$g$m/V$?$h&(%O)$V+$g$m$k$!\V
O$9$V4V$d$V8V$?$h&(%O)$V48V
($9$V4V$i$V8V$?$h&(%O)$R65(

The embedded expression must have converted an integer to a string; this is done using the $R-$ operator, which coerces
from one type to another, though it happens implicitly for embedded expressions and string concatenation. There is also an
$@)$ operator that checks the type of its operand. Finally, there is an $Y'F-6.($ operator, which checks the type of its operand,
and causes an error if it is not correct.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 7 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

4$9$"$R-$uA6$?$h&(%O)$V"V
8$9$+DZ$@)$@'A$?$h&(%O)$:4%)(
.$9$+$Y'F-6.($@'A$?$h&(%O)$+
O$9$Vf&V$Y'F-6.($@'A$?$Y66-6
($9$+D"$R-$@'A$?$h&(%O)$+

On to frames, the core data structure of the language. Frames are arranged in a hierarchy: one frame nested inside another,
this is called containment. Attributes in containing frames are available to contained frames:

4$9$"
8$9$G
$$a$9$4$`$!$?$h&(%O)$#
Q

If there are multiple candidates, the closest one is the one chosen (i.e., the one which is found first traversing starting with the
immediate container):

4$9$"
8$9$G
$$4$9$!
$$.$9$G
$$$$a$9$4$`$!$?$h&(%O)$\
$$Q
Q

This is called contextual lookup. Multiple identifiers can be put together using a $D$ to access inside frames:

4$9$G
$$a$9$"
Q
8$9$4Da$`$!$?$h&(%O)$#

And that works upward too:

4$9$G
$$a$9$"
Q
8$9$G
$$.$9$4Da$`$!$?$h&(%O)$#
Q

Now, something unexpected happens when using this notation, compared with most other languages. A reference is not
considered to be pieces: it is atomic.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 8 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

4$9$G$?$:64;($!
$$a$9$"
Q
8$9$G
$$4$9$G$?$:64;($\
$$$$C$9$!
$$Q
$$.$9$G
$$$$a$9$4Da$`$!$?$h&(%O)$#
$$Q
Q

Although the closest match of $4$ is frame 2, it does not contain an attribute $a$, so it must not be the correct $4$. Resolution
can continue and consider other $4$ values until one is matched! This will find frame 1, which does have an $a$.

There are other ways to generate frames beyond typing them literally. Templates are prototype frames, like classes are
prototype objects. It might be fair to call templates abstract frames in the Java or C# sense of the word. This measure is
called inheritance, as it is in object-oriented languages; a frame inherits a template or the template is an ancestor of the
frame.

47A;<%$9$R(;<%4A($G
$$a$9$C$`$!
Q
4$9$47A;<%$G
$$C$9$!
Q$?$h&(%O)$G$a$9$\$$C$9$!$Q

Notice that $47A;<%$ does not produce an error for lacking $C$, because the attributes in it weren't evaluated until it was
instantiated. The instantiation also amended the template by adding $C$. Like classes, templates can also inherit from other
templates and create derivatives of them:

47A;<%$9$R(;<%4A($G
$$a$9$C$`$!
Q
87A;<%$9$R(;<%4A($47A;<%$G
$$C$9$v$g$\
Q
v$9$+
8$9$87A;<%$G$Q$?$h&(%O)$G$a$9$,$$C$9$#$Q

When instantiated, the new frame can perform lookups into the containers of the location where it was instantiated and into
the containers of its ancestors, that is, the containers of the template that defined it, and any ancestors of that template. This
is described in great detail in the more advanced sections. This feature, coupled with contextual lookup, is the useful basis to
the Flabbergast language.

Like Java and C#, templates can only inherit a single parent. In Java and C#, this is mostly a concern over how to handle
methods with the same name inherited from both parents. Flabbergast has an additional reason not to encourage this: how to
combine the ancestry of the two templates. Java and C# work around their lack of multiple inheritance issues using
interfaces. In Flabbergast, there is no need for interfaces, since those are a by-product of a type system that Flabbergast
doesn't have. The consumer of a frame can pluck the attributes it needs out of that frame; it doesn't need to define a type.
Frames also don't have methods, as attributes can perform computation, so there are no type signatures to get right.

Like object-oriented languages, in addition to adding new things, template inheritance can also replace existing things:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 9 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

47A;<%$9$R(;<%4A($G
$$a$9$C$`$!
$$C$9$v$g$+
Q
87A;<%$9$R(;<%4A($47A;<%$G
$$C$9$v$g$\
Q

Because there are no methods, there are no signatures to match. It will be generally necessary to have the replacement
return something of the same type, but this is not a strict requirement.

An unusual feature of Flabbergast is the ability to remove attributes:

47A;<%$9$R(;<%4A($G
$$a$9$C$`$!
$$C$9$v$g$+
Q
87A;<%$9$R(;<%4A($47A;<%$G
$$C$9$_6-<
Q

In most other languages, this would break the class since any references to the deleted method or field would be invalid, but
in Flabbergast, any references to the removed attribute follow normal lookup and can find the value elsewhere.

Templates can also act as functions. Undefined attributes are parameters, and a single attribute can act as a result:

)M546($9$R(;<%4A($G
$$a$9$s(M5&6(O
$$N4%5($9$a$g$a
Q
8$9$*)M546($G$a$9$"$Q/DN4%5(

The $s(M5&6(O$ attribute definition defines an attribute to be present, but contain an error, forcing the user of a template to
replace this value.

For convenience, Flabbergast provides alternate syntax for consuming such a template:

8$9$)M546(*a$9$"/

Unnamed values are placed in an $46I)$ attribute.

)5;7-F7)M546()$9$R(;<%4A($G
$$$$46I)$9$s(M5&6(O
$$$$N4%5($9$:-6$a$9$46I)$s(O5.($4..$`$a$g$a$P&A=$4..$9$Z
Q
.$9$)5;7-F7)M546()*+T$mT$"/
O$9$)5;7-F7)M546()*46I)$9$+$R=6-5I=$"/

This means that function-like template can offer both variadic and non-variadic calling conventions. It is an error to specify
both $46I)$ and have unnamed arguments. If you find templates a clunky way to do this, there is a special syntax to make it
easier:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 10 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

)5;7-F7)M546()$9$:5'.A&-'*46I)/$:-6$a$9$46I)$s(O5.($4..$`$a$g$a$P&A=$4..$9$Z

There is an entirely different way to generate frames: from existing frames using the fricasse expressions. These work
something like SQL or XQuery statements to generate new frames from existing frames, as SQL generates new tables from
existing tables and XQuery generates new trees from existing trees.

4$9$G$a$9$!$$C$9$\$$v$9$+$Q
8$9$:-6$'$9$b4;(T$N$9$4$u(%(.A$'$9$N$`$!$?$h&(%O)$G$a$9$\$$C$9$+$$v$9$m$Q
.$9$:-6$N$9$4$s(O5.($N$`$4..$P&A=$4..$9$Z$?$h&(%O)$#

These are the essential features of the language. Many other built-in expressions are provided, including an $@F$ expression,
other ways to generate frames, access to external libraries, more variants of the fricasse expression, and more subtle ways
to lookup identifiers.

Core Concepts
There are two core concepts in Flabbergast: contextual (dynamic) lookup and inheritance. Both of these exist in the context
of frames, which are the primary data structure. They somewhat resemble objects in Python, Perl and JavaScript.

A frame is a map of names to values, including other frames. Each frame is immutable upon creation. The values in the
frame can be expressions (i.e., dynamically computed when the frame is created); there are no methods as there are in other
object-oriented languages. Expressions can reference each other and the Flabbergast interpreter will determine the correct
evaluation order. Although frames cannot be modified, new frames can be created from existing frames using fricasse
($:-6$) expressions that allow generation of frames based on the values in existing frames, much like SQL or XQuery
statements produce new tables or trees from existing tables or trees, respectively. Frames can also be instantiated from
templates, which are essentially unevaluated frames (i.e., the values of the attributes have not yet been computed).

Each frame also has an evaluation context. In most languages, there are multiple scopes in which variables can be found.
For instance, in C, the compiler tries to resolve a variable in the current block and proceeds through each containing block,
then checks the function parameters, and finally global variables. Java is considerably more complicated as it needs to check
not only the enclosing blocks and the method parameters, but also the fields of the class, and it has to make a distinction
between static and instantiated fields, and inner classes are even more involved as the containing classes have to be
checked. Flabbergast's algorithm for resolution is very simple, but can yield very complicated results.

Flabbergast uses contextual lookup. It is easiest to think of resolution as having two dimensions: containment and
inheritance. When resolving a variable, the language will first look for an attribute of the same name in the current frame; if
none exists, it will look in the containing frame (i.e., the frame in which the current frame is an attribute) and will continue to
examine containers until a matching frame is found. If there is no match, resolution will continue in the parents of the
template; that is, it will go to the context in which the template was defined and search through the containing frames there. If
that yields no matches, resolution will proceed back through the template's template's containers and back until there are no
more contexts.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 11 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

3, 5 6

2, 4

a:4
b : "foo"
c:a&b
a:3
b : "foo"

1
a:4
b : "foo"
c : "foo4"
Inherited By
Template
Frame

In the figure, there are two templates, shown in colour, and frames, shown in grey. The frame containment is indicated by
physical containment and inheritance is shown by arrows. When resolution inside of the frame marked 1 is needed, resolution
begins in the frame itself, then proceeds through the frames, as indicated by their numbers. Note that some frames are
considered multiple times due to the template and the frame sharing some containment; this is inconsequential, as it will
either be found the first time, or fail every time. Note that templates themselves are not checked: only the frames in which
they were defined or amended.

Resolution has an extra complexity: chained accesses. Since frames can be nested, it is desirable to access the attributes of
an inner frame using the $aDC$ syntax. In most languages, resolution stops when the first name match is met (e.g., in Java, if
there is a parameter $&'A$F--$ and a class field $uA6&'I$F--$, then $F--D.=46BA*+/$ will fail to compile because $F--$ has been
resolved to the parameter, which is an $&'A$ and so does not have the $.=46BA$ method) while Flabbergast will attempt to find
the one you meant. In the case of $aDC$, if a frame $a$ is found but it does not contain an attribute $C$, then the language
assumes that this was not the $a$ intended and continues looking for an $a$ does does contain an attribute $C$. This means
that the expression $aDC$g$aDv$ can have two different frames referenced for the first and second $a$! For instance, below,
$8Dv$ will be 12 and the $4$ in the $4Da$ reference will be the top-level $4$ while the $4$ in the $4DC$ reference will be $8D4$:

4$9$G$a$9$+$Q
8$9$G
$$4$9$G$C$9$m$Q
$$v$9$4Da$g$4DC
Q

In general-purpose programming languages, this idea sounds like madness, but Flabbergast is not a general-purpose
programming language: it is intended to be used for writing configuration files. In that case, this feature allows brevity and
clarity. If an SMB share looks for $5)(6)D4O;&')$, it will pick up the one that is closest to the expression using it and, if the
closest one does not provide that information, it must be somewhere else. Perhaps the best way to think of it is how human
languages work:

My father hates cats even though my mum likes them, so my parents never got a cat. When my sister moved out, she
got a cat. My mum loves playing with her cat.

In the last sentence, to whom does her refer? While my mum is the closest noun that could match her, it has been previously
established that my mum does not have a cat, so my mum's cat wouldn't make sense. Because we treat her cat as a unit, we
contextually keep looking for a her that does have a cat, which would be my sister. Conceptually, this is how Flabbergast's
resolution algorithm works: it finds the match that makes the most contextual sense.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 12 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Inheritance allows creation of attributes, in addition to providing a history for contextual lookup. A frame or template is a
collection of key-value pairs, where each key is a valid identifier and a value can be any expression. A template can be
amended at the time of instantiation or through the $R(;<%4A($ expression, which creates a new template that copies all the
existing attributes, less the amended ones. In most object-oriented languages, fields and methods can be overridden (i.e.,
replaced with new code). Similarly, attributes can be overridden with new expressions. Some languages allow access the
overridden method through special keywords (e.g., Java's $)5<(6$, C#'s $84)($, or Python's $)5<(6*/$). Flabbergast permits
accessing the original attribute, but a new name must be specified; there is no default name like $)5<(6$. Unlike most
languages, Flabbergast permits deletion of an attribute. Because of contextual lookup, any other attributes referencing the
deleted attribute will look elsewhere.

Since attributes can refer to each other, it is the interpreter's duty to determine the order to evaluate the expressions. This
means that attributes can be specified in any order (unlike C and C++). In fact, contextual lookup makes it impossible to
determine to what attributes references refer until evaluation time. One unusual effect is that the inheritance path of a frame
can be changed at runtime (i.e., the class hierarchy is not determined at compile-time)! In fact, since templates can be
instantiated in different contexts, it is possible for the same declaration to be used in different contexts that create two
different frame inheritance paths. This is the kind of stuff that can be used for good or evilthere are legitimate reasons to re-
parent frames, but it can be very confusing and cause unexpected behaviour.

The interpreter must be able to linearise the order in which it will perform evaluations. If the expression evaluation contains a
cycle, then it is not possible to evaluate any of the expressions in the cycle. This is called circular evaluation. There are
pseudo-cycles that are acceptable: the expressions can refer to one-another circularly so long as they don't need the value.
This happens mostly during contextual lookup:

a$9$G
$$E$9$m
$$v$9$C
Q
C$9$aDE

Here, $a$ as a frame, cannot be completely evaluated because the attribute inside $v$ depends on the value of $C$, which in
turn, depends on $E$, inside of $a$. Although there is cross-reference into and out of $a$, there is an order that works: evaluate
$a$ to be a frame with attributes $E$ and $v$ (though do not evaluate them), evaluate $aDE$i to be 4, evaluate $C$ to be 4, and
finally $aDv$ to be 4. Here is an example of true circularity:

a$9$C
C$9$a

or even more succinctly:

a$9$a

Usually, the intended meaning of this expression is:

G
$$a$9$w--X5<$a$@'$H-'A4&'(6
Q

Syntax

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 13 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

In Flabbergast, all keywords start with a capital letter and identifiers start with a small letter, making them easily
distinguishable. There are also a number of special characters used for operators. Comments begin with $?$ and terminate at
the end of the line. For the purposes of code formatting, comments preceding an attribute are assumed to be associated with
it.

Types and Constants


Flabbergast has a small handful of types: integers ($@'A$), floating-pointer numbers ($:%-4A$), Boolean values ($3--%$), text
strings ($uA6$), binary strings ($3&'$), frames ($:64;($) and templates ($R(;<%4A($).

Integral and floating-point number literals are specified in the familiar way. They can also be manipulated using the typical $`$,
$c$, $g$, $>$ and $x$ operators. In mixed-type expressions, integers are automatically promoted to floating-point numbers. They
also can be compared using $kk$, $pk$, $i$, $ik$, $j$, $jk$, and $ikj$. The $ikj$ operator will be familiar to Perl and Ruby
programmers: it compares two values and returns -1, 0, or 1 if the left operand is less than, equal to, or greater than the right
operand, respectively. There is also a unary negation operator $c$. A few floating-point exceptional tests are provided: $@)
:&'&A($ and $@)$b4b$ to check if the number is finite or not-a-number in the IEEE sense, respectively. Also, the floating-point
constants $b4b$, $@'F&'&AC$, $:%-4A[4a$, and $:%-4A[&'$, and integer constants $@'A[4a$ and $@'A[&'$ are provided.

The Boolean constants provided are $R65($ and $:4%)($ that can be manipulated using the operators $dd$, $nn$, and $p$. They
can also be compared using the full set of comparison operators; true is considered to be greater than false. There is no
separate exclusive-or operator as $pk$ serves this role. Both $dd$ and $nn$ are short-circuiting. As a confusing side benefit, a
implies b can be written as $4$ik$8$.

String literals, delimited by double quotation marks, can cover multiple lines and can contain embedded escape sequences
and expressions. The escape sequences supported include the single-character escapes supported by C, triplets of octal
digits, pairs of hexadecimal digits, and Unicode-friendly quadruplets of hexadecimal digits. Embedded expressions start with
$t*$, followed by an expression, and terminated with a matching $/$; the expression must return a string, or a type that can be
coerced to a string. Strings can also be joined together with the $d$ operator. For example, $4$, $8$ and $.$ will have the same
value and the reference to $a$, which is an integer, is converted to a string:

a$9$+
4$9$VF--kt*a/t'V
8$9$VF--kt*a/
V
.$9$VF--kV$d$a$d$Vt'V

Sometimes, attribute names are provided as strings and, since not all strings are valid attribute names, it is useful to have a
way to create a string that is a valid attribute name. By placing $y$ before a valid identifier, a string with the identifier name will
be created.

a$9$yF--$kk$VF--V$?$R65(
C$9$y"$?$Y66-6

Binary strings are handled mostly by library functions as a way to pass binary data around, including conversion to and from
text strings, hashing, and database interaction.

Frames are collections of attributes. Literal frames are specified starting with $G$, followed by a list of attributes, and
terminated with a matching $Q$. Each attribute is a name, followed by $9$, and an expression. Frames inherit the context of the
frame in which they are defined. Templates look similar except that they are preceded by the $R(;<%4A($ keyword. There are
two important differences between templates and frames: frames are immutable while templates can be manipulated and
variable resolution can look inside frames, but not inside of templates. Neither can be coerced to strings. More details on

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 14 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

frames are provided later.

There is also a special $b5%%$ constant which can be checked for using the $@)$b5%%$ operator. The null value cannot be used
in any comparison operator and doing so will cause an error. The null value is not the same as an undefined variable. There
is a null coalescence operator $ee$ that can substitute a default value if the left operand is null. Unlike most languages, null
should be used extremely sparingly in Flabbergast: it is usually preferable to let contextual lookup find appropriate values.
Null should mean this value is not helpful and that's the final word instead of the usual meanings of I don't know or this
does not exist.

a$9$b5%%
C$9$a$ee$+$?$h&(%O)$+
v$9$a$kk$b5%%$?$Y66-6
E$9$a$@)$b5%%$?$h&(%O)$R65(

The $R-$ operator can be used to coerce values to other types. Integral and floating-point types can be inter-converted, with
appropriate truncation, and converted to strings.

The $@)$ operator checks whether a value is a particular type and returns the result as a Boolean value.

The $Y'F-6.($ operator ensures that a value is of a particular type, if not, an error occurs.

N$9$V+V$Y'F-6.($uA6$?$V+V
E$9$+$Y'F-6.($uA6$?$Y66-6
a$9$+$R-$uA6$?$V+V
C$9$m$@)$@'A$?$R65(
v$9$mD"$@)$@'A$?$:4%)(

Also see the $RC<(UF$ expression.

Special Frame Literals


Two special frame literals are provided: the literal list and the range operator.

Frames are implicitly sorted by their attribute names. The literal list is a way to create a frame with only values and the names
are set to arbitrary labels that have a guaranteed stable sorting. It is a comma-separated list of expressions starting with a $K$
and terminating with a $L$.

The $R=6-5I=$ operator produces a list with the values being numbers starting from the left operand up to, and including, the
right operand, both of which must be integers. If the right operand is the same or less than the left, the list returned will be
empty.

The values of the following frames all have the same values in the same order:

a$9$K$!T$\T$+$L
C$9$!$R=6-5I=$+
v$9$G
$$4$9$!
$$8$9$\
$$.$9$+
Q

Flow Control

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 15 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

A conditional expression is provided: $@F$, an expression which returns a Boolean value, $R=('$, an expression to be returned
if the first expression is true, $Y%)($, an expression to be returned if the first expression is false. This expression, very
importantly, impacts contextual lookup. Free identifiers in the $R=('$ and $Y%)($ expressions are not resolved unless that
expression is selected. This means that they can contain invalid references without causing an error. For instance, $C$ will be
5 and no error will occur even though $v$ is not defined.

a$9$"
C$9$@F$a$i$!Z$R=('$a$Y%)($v

The $Y66-6$ expression raises an error, stopping execution of the whole program. Any expression attempting to consume the
return value of this expression will fail to evaluate.

a$9$"
C$9$@F$a$i$!Z
$$R=('$a
$$Y%)($Y66-6$VR=($N4%5($t*a/$&)$A--$%46I(DV

Lookup
A period-separated list of identifiers forms a free variable to be resolved by contextual lookup; this is called contextual lookup.

4$9$"
8$9$G
$$.$9$4$`$+
Q
a$9$8D.

Here, in $8D.$, lookup will start in the current frame, which does not contain $4$, so lookup will continue to the containing
frame, which does have $4$. For $a$, it will look for a frame $8$ which contains an attribute $.$.

A period-separated list of identifiers can also be appended to any expression, in which case it will do exact matching starting
from the expression supplied; this is called a direct lookup. The keyword $R=&)$ gives access to the frame where the
expression is being evaluated, effectively forcing direct lookup. Using parentheses or the result of an expression will also
result in direct lookup.

$a$9$!
$4$9$G
$$$a$9$+
$$$C$9$R=&)Da$`$!$?$h&(%O)$m
$Q
$8$9$*4/Da$?$h&(%O)$m

The keyword $H-'A4&'(6$ access the parent of the frame (either the current frame if it is used alone, or the preceding frame if
used in an contextual or direct lookup).

$4$9$!
$8$9$G
$$$4$9$H-'A4&'(6D4$?$h&(%O)$!
$Q

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 16 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

The $w--X5<$ expression performs a remote contextual lookup; $w--X5<$4D8D.$@'$a$ will start contextual lookup for $4D8D.$
starting from the context of the frame $C$, rather than the current context.

Here is non-trivial example uses of all lookup styles:

&$9$m
4$9$G
$$=$9$&$c$!$?$R=&)$F64;($O-()$'-A$.-'A4&'$&T$85A$A=($.-'A4&'(6$O-()D$h&(%O)$m$c$!$k$+
Q
a$9$4D=$?$P&%%$8($+
C$9$4D&$?$P&%%$8($4'$(66-6
v$9$w--X5<$&$@'$4$?$P&%%$8($m
E$9$G
$$4$9$G
$$$$&$9$\
$$Q
$$a$9$4D=$?$P&%%$8($+
$$C$9$4D&$?$P&%%$8($\
$$v$9$w--X5<$&$@'$4$?$P&%%$8($\
$$N$9$*4/D=$?$P&%%$8($4'$(66-6
Q

In $4$, contextual lookup searches for an $&$, which does not exist in the current frame, but does exist in its container. In $a$,
contextual looks for an frame $4$ that contains an attribute $=$, which it finds at the top-level. In $C$, although $&$ is accessible
from the frame $4$, it does not exist in $4$, so $4D&$ fails to find a matching frame. However, in $v$, a remote lookup searches
for $&$ starting from $4$, which is found in exactly the same way as when computing the value for $4D=$. Inside $E$, the situation
is more complicated as another frame named $4$ is created. Searching for $4D=$, as $EDa$ does, first checks the frame $ED4$,
but this frame lacks an $=$ attribute, so lookup continues, instead finding the top-level frame. In $EDC$, lookup for $4D&$ will
match the $ED4$ frame as it does have an $&$ attribute. In both $EDv$ and $EDN$, searching for $4$ yields $ED4$. In the case of
$EDv$, doing a remote lookup inside $ED4$ for $&$ will find the attribute inside it. In the case of $EDN$, the parentheses have
broken the lookup into a contextual lookup ($4$) and a direct get ($D=$); this is an error as the matched $4$ ($ED4$) does not
have an attribute $=$.

This is the most complicated part of the language, but also the most useful.

The pattern $@F$a$@)$b5%%$R=('$b5%%$Y%)($*a/DC$ tends to show up frequently. The nullable lookup operator, makes this
$aeDC$.

Fricasse Expressions
Although frames are immutable, it is possible to create new values from existing frames using fricasse expressions. These
expressions take a collection of input frames an iterate over the attributes they share. The concept was based on XQuery's
FLOWR expressions, which are based on SQL queries. It should be familiar to users of Haskell and LISP's $;4<$ and $F-%O$
functions, C#'s LINQ expressions, Python's list and dict comprehensions, or Perl's $;4<$ and $I6(<$ constructs. Conceptually,
the expression has three parts: a source, optional manipulations, and a sink. The source extracts data from frames and
produces a context in which each subsequent expression will be evaluated. The manipulations can filter can discard any
contexts that do not meet certain requirements, reorder the data, or compute intermediate values. The sink produces a value
from the contexts: either a new frame, or a single value for a reduction.

There are two sources provided: the combined attributes of frames, and, prepared context frames. In all cases, the select is
done over a collection of input frames and all the attributes of the input frames. The following example shows the first part of
a fricasse expression for different sources over the same input frames. In the first three cases, the source will iterate over
the union of all the attributes in the frames $a$, $C$, and $v$ and each context will have $4$, $8$, and $.$ bound to the values in

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 17 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

the corresponding frames, or $b5%%$ if there is no corresponding value. For the values only source, $&$, this is all the context
will contain. In the case of $J$, the attribute name itself will be bound as $'$ in a string, using the special $b4;($ value. In the
case of $X$, the position will be provided using the special $U6O&'4%$ value; indexing starts from 1.

a$9$G
$$<$9$!
$$M$9$\
Q
C$9$G
$$<$9$+
$$M$9$m
Q
v$9$G
$$<$9$"
Q
&$9$:-6$4$9$aT$8$9$CT$.$9$v$DDD
$$?$P&%%$.-')&O(6$G$4$9$!$$8$9$+$$.$9$"$QT$G$4$9$\$$8$9$m$$.$9$b5%%$Q
J$9$:-6$'$9$b4;(T$4$9$aT$8$9$CT$.$9$v$DDD
$$?$P&%%$.-')&O(6$G$4$9$!$$8$9$+$$.$9$"$$'$9$V<V$QT$G$4$9$\$$8$9$m$$.$9$b5%%$$'$9$VMV$Q
X$9$:-6$'$9$U6O&'4%T$4$9$aT$8$9$CT$.$9$v$DDD
$$?$P&%%$.-')&O(6$G$4$9$!$$8$9$+$$.$9$"$$'$9$!$QT$G$4$9$\$$8$9$m$$.$9$b5%%$$'$9$\Q
%$9$:-6$Y4.=$K$aT$CT$v$L$DDD
$$?$P&%%$.-')&O(6$G$<$9$!$$M$9$\$QT$G$<$9$+$$M$9$m$QT$G$<$9$"$Q

The prepared frame source, $Y4.=$, is meant for library functions to produce iterable sources of data. One could imagine a
library function matching a regular expression and returning the matched groups. It becomes the responsibility of the source
to provide sensible attributes in each frame. In the example, $v$ makes for an awkward environment since $M$ is not bound,
and the $Y4.=$ source is not obligated to correct the inconsistency.

Optionally, a $P=(6($ clause can be used to filter the results. It must return a Boolean value.

a$9$!$R=6-5I=$,
&$9$:-6$4$9$a$P=(6($4$j$"$DDD$?$h&(%O)$G$4$9$#$QT$G$4$9$,$Q

Finally, a sink is needed to produce a value from the contexts. Three are supported: a reducer, an anonymous frame
generator, and a named frame generator. The reducer and the anonymous frame generator both support ordering.

The reducer works as a typical fold/reduce operation:

a$9$!$R=6-5I=$,
C$9$:-6$N$9$a$s(O5.($N$`$4$P&A=$4$9$Z

The initial value of the accumulator, $4$, is set to zero and the reduce expression is repeated for each of the contexts. In each
context, the accumulator will be bound to the previous value. The reducer can support ordering operations, shown later, on
the contexts to choose the reduction order.

Sometimes, it is useful to compute intermediate values during iteration. For this, a $w(A$ clause can be added:

a$9$!$R=6-5I=$,
C$9$:-6$N$9$a$w(A$E$9$N$g$N$`$N$P=(6($E$j$m$g$N$u(%(.A$E

It is also possible to produce a running value using $B..5;5%4A($:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 18 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

a$9$!$R=6-5I=$,
.5;5%4A&N(7)5;$9
$$:-6$N$9$a
$$$$B..5;5%4A($.566('A7)5;$`$N
$$$$$$P&A=$.566('A7)5;$9$Z
$$$$u(%(.A$.566('A7)5;

The anonymous frame generator produces a new frame with each value being the result of an expression. The names of the
frames are generated automatically in the same way as if they had been generated by a literal list or $R=6-5I=$ expression.

a$9$,
C$9$:-6$N$9$*!$R=6-5I=$a/$u(%(.A$N$g$N$?$W6-O5.()$4$%&)A$-F$)M546()

Because multiple input frames can be provided, much like LISP's variadic $;4<$, it also functions like Haskell's $v&<$:

a$9$K$!T$\T$+$L
C$9$K$mT$"T$#$L
v$9$:-6$4$9$aT$C$9$8$u(%(.A$4$`$8$?$Y%(;('AcE&)($)5;$-F$A=($%&)A)

The anonymous frame generator can support ordering operations, shown later, on the context to choose the order of the
output.

The named attribute frame generator produces a frame where the element names are provided as strings:

a$9$!$R=6-5I=$+
C$9$:-6$4$9$a$u(%(.A$VF--t*a/V$9$a$?$W6-O5.()$A=($F64;($G$F--!$9$!$$F--\$9$\$$F--+$9$+$Q

The name provided must be a valid identifier, which is not true of all strings, otherwise an error will occur. This named
attribute frame generator does not support ordering operations since the order of attributes in a frame is controlled by their
names.

Presently, there are two ordering operations: $s(N(6)($ reverses the order of the input and $U6O(6$3C$ produces a sorting item.

a$9$c+$R=6-5I=$+
C$9$:-6$4$9$a$$s(N(6)($$u(%(.A$4$?$h&(%O)$K$+T$\T$!T$ZT$c!T$c\T$c+$L
v$9$:-6$4$9$a$$U6O(6$3C$*@F$4$i$Z$R=('$c4$Y%)($4/$Y'F-6.($@'A$u(%(.A$4$?$h&(%O)$K$ZT$c!T$!T$c\T$\T$c+T$+$L

Note that if two values have the same sort key, in the example -1 and 1 do, then the order between them is not guaranteed.
Any type that can be compared using the $ikj$ can be used as a sort key, but all must be of the same type.

Frames and Templates


In addition to literal frames, frames can be instantiated from templates. The instantiation can also amended a template by
adding, removing, or overriding attributes. The syntax for instantiation is an expression yielding a template followed by $G$, an
optional list of amendments, and terminated by $Q$. Templates are created in a syntax similar to literal frames: $R(;<%4A($G$, a
list of attributes, followed by $Q$.

F--7A;<%$9$R(;<%4A($G$4$9$8$`$m$Q
F--$9$F--7A;<%$G$8$9$+$Q$?$h&(%O)$G$4$9$,$$8$9$m$Q

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 19 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Templates can also be derived using a syntax that is a hybrid of the two: $R(;<%4A($, an expression for the template from
which to derive, followed by $G$, an optional list of amendments, and a terminating $Q$. It's important to note that deriving a
template, even with no changes, amends it because it adds additional lookup scopes. In general, it's useful think of the curly
braces and capturing scope. In this example, $F--\7A;<%$ is capturing the scope inside of $a$, making $8$ available to its
descendants.

F--7A;<%$9$R(;<%4A($G$4$9$8$`$m$Q
a$9$G
$$F--\7A;<%$9$R(;<%4A($G$Q
$$8$9$!
Q
C$9$aDF--\7A;<%$G$Q$?$h&(%O)$G$4$9$"$Q

There are several amendment attributes, not all of which can be used in all contexts:

$9$, followed by an expression, defines an attribute to be the supplied expression. If there previously was an attribute of
the same name, it is discarded.
$9$s(M5&6(O$ creates an attribute that is always an error. This can be thought of as an abstract attribute, in the
C++/Java/C# terminology. This is not permitted during instantiation.
$9$_6-<$ deletes an attribute. The attribute must already exist, so this is not valid when declaring a new template.

$`$, followed by an identifier, then $9$, followed by an expression, will replace an attribute but allows the previous value to
be bound to the identifier supplied. The attribute must already exist, so this is not valid when declaring a new template.
$`9$G$, followed by a list of amendments, terminated by $Q$, performs template amendment. It is short-hand for
$`-%OA(;<%4A(9$R(;<%4A($-%OA(;<%4A($G$DDD$Q$ with the convenience of not having to choose a name.

$9$z)(O$ indicates that a value is expected to be available through lookup. It does not actually do anything; it is merely a
way to explain intentions to others and provide a place to hang documentation. It can be thought of as a weak version of
$s(M5&6(O$ attributes, and is usually preferable.

$9$b-E$, followed by an expression, creates an attribute, but evaluates is eagerly, in the current context, much like the
function call convenience syntax.

There is also a function call convenience syntax. In their own way, templates can act as lambdas. In frame instantiation, the
expressions are evaluated in the context of the frame created. In a function call, expressions provided are evaluated in the
current (parent) context, then placed into the instantiated template. A list of unnamed expressions can be provided and these
are collected into an $46I)$ frame. Finally, instead of returning the entire frame, the $N4%5($ attribute is returned from the
instantiated frame. For instance, the function call:

G
$$4$9$+
$$8$9$\
$$.$9$!
$$v$9$F*4T$8T$.$9$./
Q

is almost rewritten as:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 20 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

G
$$4$9$+
$$8$9$\
$$.$9$!
$$v$9$*F$G
$$$$46I)$9$b-E$K$4T$$8$L
$$$$.$9$b-E$.
$$Q/DN4%5(
Q

In this example, $.$ would be circular evaluation when using normal evaluation semantics, but because the evaluation of the
parameters happens in the containing context, this is fine. There is a subtle different too: the resulting frame's container will
not be the one where it is instantiated, but the one where it is defined.

For Java programmers, there's an analogy for the two modes of template instantiation: anonymous inner classes. Creating a
template is a bit like instantiating an anonymous inner class. If that class has multiple methods, then template instantiation
gives similar behaviour. If only one method is of interest, then it can be instantiated using function-like instantiation, much like
lambda notation in Java 8.

Data Reshaping
It's useful to remember how all the pieces of structured data manipulation in the language work. The following diagram shows
the different formats of data and the syntax that navigates between them.

Literal Frame
*+
Define
!"#$%&'"(*+
Literal List
./

Fricasse
Amend
Instantiate 012(333(4"%"5'(333
!"#$%&'"()(*+ Template )(*+ Frame Frame Concatenate
)(,-(*+
()(6$$"78(9

Fricasse
012(333(:"8;5"(333

Int, Float,
Str, or Unit

Templates can be made from scratch or from existing templates. Frames can be made from scratch, by instantiating
templates, the fricasse $u(%(.A$ operations, or the $B<<('O$ expression. Scalar values can be distilled from frames using the
fricasse $s(O5.($ operation. Scalar values can be manipulated a number of ways not shown in the diagram.

TypeOf Expression
The $RC<(UF$ expression allows type-directed lookup. This operation gets the type of a value. Rather than return that value as
a string or type type, it performs a lookup so that a user-defined value is returned.

For instance, $RC<(UF$VaV$ will perform a lookup for $)A6$ and return whatever value that is. The name of the variable looked
up is the same as the types but lower case.

The expression takes an optional prefix specified using $P&A=$: $RC<(UF$VaV$P&A=$F--$ would resolve to $F--D)A6$

This allows the $RC<(UF$ expression to change the semantics as desired. For instance, here is a case where direct

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 21 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

comparison is desired:

AC<(7&O$9$G$8&'$9$Z$$8--%$9$!$$&'A$9$\$$F%-4A$9$$+$$F64;($9$m$$'5%%$9$"$$)A6$9$#$$A(;<%4A($9$,$Q
46(7a74'O7C7A=(7)4;(7AC<($9$RC<(UF$a$P&A=$AC<(7&O$kk$RC<(UF$C$P&A=$AC<(7&O

Suppose we want to know if a type can be converted to an SQL literal:

=4)7)M%7%&A(64%$9$G$8&'$9$R65($$8--%$9$R65($$&'A$9$R65($F%-4A$9$$R65($$F64;($9$:4%)($$'5%%$9$R65($$)A6$9$R65($$A(;<%4A($9$:4%)(
.4'7a78(74'7)M%7%&A(64%$9$RC<(UF$=4)7)M%7%&A(64%$P&A=$a

We can even be craftier and convert a value by lookup:

.6(4A(7)M%7%&A(64%$9$G
$$8&'$9$R(;<%4A($G$N4%5($9$<6-N&O(6D8%-87)A46A$d$5A&%)7%&8D8&'7A-7=(a7)A6*&'<5AT$5<<(6.4)($9$R65(/$d$<6-N&O(6D8%-87('O$Q
$$8--%$9$R(;<%4A($G$N4%5($9$@F$&'<5A$R=('$VA65(V$Y%)($VF4%)(V$Q
$$&'A$9$R(;<%4A($G$N4%5($9$&'<5A$R-$uA6$Q
$$F%-4A$9$$R(;<%4A($G$N4%5($9$&'<5A$R-$uA6$Q
$$F64;($9$R(;<%4A($G$N4%5($9$Y66-6$VH4''-A$.-'N(6A$F64;($A-$u{wDV$Q
$$'5%%$9$R(;<%4A($G$N4%5($9$VbzwwV$Q
$$)A6$9$$R(;<%4A($G$N4%5($9$<6-N&O(6DM5-A(7)A46A$d$5A&%)7%&8D)A67().4<(*&'<5AT$A64')F-6;4A&-')$9$<6-N&O(6DA64')F-6;4A&-')/$d$<6
$$A(;<%4A($9$$R(;<%4A($G$N4%5($9$Y66-6$VH4''-A$.-'N(6A$A(;<%4A($A-$u{wDV$Q
Q
N4%5($9$*RC<(UF$a$P&A=$.6(4A(7)M%7%&A(64%/*&'<5A$9$a/

That is, use $RC<(UF$ to find a function-like template and then call it on the value.

Miscellaneous
The $w(A$ expression allows binding a value to a new name. For example, $w(A$4$9$+$@'$4$g$4$. This is a convenient way to
eliminate common subexpressions. Be advised that the normal short-circuiting rules do not apply: all the values in the
expression must be evaluated first. Multiple attributes can be bound at once (e.g., $w(A$4$9$+T$8$9$m$@'$4$g$4$`$8$g$8$).

The $B<<('O$ operators concatenates two frames. The attribute names are the same as if a literal list had been used. This
means that $G$4$9$"$Q$B<<('O$K$#$L$ will produce the same frame as $K$"T$#$L$.

The $:6-;$ expression allows importing external content into the program. This does two jobs: allows accessing libraries and
allows access information for the program being configured. The $:6-;$ keyword is always followed by a URI. The $%&89$ URI
is used for the standard library. By convention, it is best to do all the importing at the start of a file:

F--7%&8$9$:6-;$%&89F--

Presently, there are handlers for:

SQL databases ($)M%9$)

local files ($F&%(9$ and $6()9$)

FTP and HTTP URLs ($FA<9$, $FA<)9$, $=AA<9$, and $=AA<)9$)

VM-specific settings using $J4N4D%4'IDuC)A(;DI(AW6-<(6AC$ on the JVM and


$uC)A(;DH-'F&I564A&-'DH-'F&I564A&-'[4'4I(6DB<<u(AA&'I)$ ($)(AA&'I)9$)

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 22 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

environment variables ($('N9$)

Flabbergast runtime information ($.566('A9$)

version : From env:EXAMPLE_VERSION release_db : From sql:postgresql://o_0@db.example.com/release sql_lib :


From lib:sql

release_versions : sql_lib.retrieve { connection : release_db, sql_query : "SELECT version, artifact, checksum FROM
release_info ORDER BY push_date WHERE version == '(token)'" }

Implementation-specific keywords start with $r$. They should not be used in most code, but are often present in libraries to
support binding to the underlying platform.

Using the Language


The language is meant for creating configurations. What, precisely, is a configuration? Or, more specifically, how is it different
from regular code?

Certainly, Flabbergast is a bad choice for writing a GUI application, or a data processing pipeline. It's almost useful to think of
Flabbergast as something like a compiler: it takes highly structured data and outputs very simple data. Effectively, it is meant
to render data. What the language is attempting to do is compress the duplication in a very ad-hoc way, as a macro system
does. Real compilers for real languages are large, complicated, and, hopefully, well-designed. Flabbergast aims to help you
put together a very simple language with almost no effort, but, unlike most macro systems, it's going to have rather
sophisticated descriptions of data. As such, it's not going to do everything right; it's going to rely on the user to put in
moderately sane input and that the downstream consumer will validate the input.

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. Everything is malleable and done in such a way that it can be changed even if the base
version didn't anticipate that change. There's no concept of Java's $F&'4%$, or C++'s $.-')A$.

Most languages, particularly object-oriented languages, have a lot of plumbing: taking data from one place and copying it to
another. Most constructors in object-oriented languages spend their time stuffing parameters into fields. There is a push in
multi-paradigm object-oriented languages, including Python, Scala, Ruby, Groovy, Boo, and Nemerle, to have the compiler
write the plumbing, freeing the programmer to work on the real logic. Flabbergast has a different approach: don't have
plumbing at all. Define the data where it should be defined and use contextual lookup to pull data from the wherever. Copying
data is generally a sign that contextual lookup is not being used effectively.

Although Flabbergast has the $s(M5&6(O$ attribute definition, it should almost never be used. This is one of the most frequent
mistakes of novice programmers. If there's a value needed, just use it; there's no need force the consumer of a template to fill
in the blank. The real use case is for things that must be provided and unique. For instance, the name of an SMB share is
probably best defined with $s(M5&6(O$, but the list of users that can access the share should certainly not use $s(M5&6(O$. It's
okay that a user who instantiates a share template without providing a users list somewhere will cause a lookup error: failure
to provide an appropriately name value is a failure to consume that API correctly and, indeed, this was noted by an error
being produced. There's no need to make this some how more explicit. The $z)(O$ attribute definition provides an advisory
version of $s(M5&6(O$ that indicates that a value should be supplied, but does not stipulate that it needs to be included directly.

The most important feature of Flabbergast is overriding. When starting out with Java or C#, understanding how to divide
things up into objects is the hard part. When starting out with ML or Haskell, understanding how to make things stateless is
the hard part. When starting out with Flabbergast, understanding how to make things easy to override is the hard part.

Interfaces

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 23 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

In object-oriented languages, there is typically some convention surround how to tell if an object is consumable in a particular
situation. Statically-typed object-oriented languages typically have interfaces, in the Java or C# sense. These are functions
of the type system: since each expression needs a type and multiple inheritance is not permitted, an interface provides a type
that any object can fulfill outside of the inheritance hierarchy. Dynamically-typed object-oriented languages, particularly
Python, JavaScript, and Ruby, eschew this and proudly extol the benefits of duck typing: that is, call a method and expect it
to work.

Flabbergast is necessarily dynamically-typed by virtually of being dynamically-scoped. Therefore, interfaces are definitely of
the duck-typing variety. Since methods aren't present, the interface is still simpler: it is the attributes that a frame is expected
to have and, possibly, expected types for those attributes. Using the $Y'F-6.($ operator is a polite way of insisting that certain
types are provided from an interface.

Often, the caller has some driver to convert code. For instance, this is a completely reasonable block of Python:

)A6)$k$KL
F-6$&A(;$&'$&A(;)9
$)A6)D4OO*V'4;(9$x)$.-5'A6C9$xOV$x$*&A(;D'4;(T$&A(;D.-5'A6C//
6(A56'$Vt'VDJ-&'*)A6)/

Indeed, this could be translated into Flabbergast as follows:

)A6)$9$:-6$&A(;$9$&A(;)
$$s(O5.($Vt*4../'4;(9$t*&A(;D'4;(/$.-5'A6C9$t*&A(;D.-5'A6C/t'V
$$P&A=$4..$9$VV

However, it is often simpler to make items self-rendering:

&A(;7A;<%$9$R(;<%4A($G
$$'4;($9$s(M5&6(O
$$.-5'A6C$9$s(M5&6(O
$$N4%5($9$V'4;(9$t*'4;(/$.-5'A6C9$t*.-5'A6C/t'V
Q
)A6)$9$:-6$&A(;$9$&A(;)
$$s(O5.($4..$d$&A(;DN4%5(
$$P&A=$4..$9$VV

This has two advantages: the rendering logic can be overridden and the interface is simpler. As a disadvantage, there is now
an inheritance implication for the values of $&A(;)$. However, because the template $&A(;7A;<%$ can be overridden and
replaced, the inheritance implication is flexible. In fact, it would be reasonable to have:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 24 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

&A(;784)(7A;<%$9$R(;<%4A($G
$$'4;($9$s(M5&6(O
$$.-5'A6C$9$s(M5&6(O
Q
&A(;7a;%7A;<%$9$R(;<%4A($&A(;784)(7A;<%$G
$$N4%5($9$Vi<(6)-'ji'4;(jt*'4;(/i>'4;(ji.-5'A6Cjt*.-5'A6C/i>.-5'A6Cji><(6)-'jV
Q
&A(;7<6(AAC7A;<%$9$R(;<%4A($&A(;784)(7A;<%$G
$$N4%5($9$V'4;(9$t*'4;(/$.-5'A6C9$t*.-5'A6C/t'V
Q
&A(;7A;<%$9$@F$a;%7-5A<5A$R=('$&A(;7a;%7A;<%$Y%)($&A(;7<6(AAC7A;<%
&A(;)$9$K
$$&A(;7A;<%$G$'4;($9$VB'O6(V$$.-5'A6C$9$VH4'4O4V$QT
$$&A(;7A;<%$G$'4;($9$Vl6|&''(V$$.-5'A6C$9$V@6(%4'OV$Q
L

By changing the definition for $&A(;7A;<%$, we can re-ancestor the frames using it. Effectively, Flabbergast has a kind of
multiple inheritance: there can be only one ancestor at a time, but the choice of ancestor can be varied at run time.

Subexpressions and Encapsulation


In complicated subexpressions, it is often useful to migrate common subexpressions to a $w(A$ expression. In general, $w(A$ is
less preferred to creating a new attribute in the current frame. There are places where that is not possible (e.g., inside a
fricasse expression).

There are two reasons that is preferred: debugging and overriding. Since there is no way to see the value bound in a let, it is
much better if intermediate values can be seen if the entire output is dumped. It is also possible that a user would like to
override this value. That violates all the usual object-oriented mindset about data encapsulation, but this isn't a usual object-
oriented language.

First, it can be extremely useful for debugging purposes to tinker with subexpressions. For instance, if there is a condition that
isn't working properly, it could be useful to override the condition and check if the output is at least correct. Second, the user
might be doing something sufficiently different that overriding that condition is helpful. Perhaps they need an extra clause or
there is a special case where that logic isn't appropriate.

In a language designed around exceptions, exposing the inner workings is a feature, not a bug. However, this implies a larger
interface surface, which is more difficult to maintaina balance must be struck. The language has made interface simpler, so
adding some extra complexity is not as grievous. It's also worth noting that some overrides of non-existent attribute is dead,
but not dangerous, code. As a general rule, the real description of the interface belongs in documentation (either external or
comments) that describe the interface.

When writing templates, it is good style to separate attributes into blocks: the parameters, private intermediate attributes,
and output attributes.

Name-ability
Naming things is difficult. Very difficult. The major disadvantage to dynamic scoping is that names can collide and have
unintended consequences. There are several ways to address the problems:

1. Name things well. That might sound glib, but it isn't. The traditional loop variables $&$, $J$, and $X$ are a heap of trouble in
Flabbergast. The opposite end of the spectrum $E=(6(7)5<(67(a<%&.&A7'4;()7A=4A7'-7-'(7.4'7.-'F5)($ are used is
equally unpleasant. If the name is semantically meaningful and the same term isn't overloaded (e.g., $;5$ can be the
magnetic field permeability of free space and the coefficient of friction), then it is probably a good choice and collisions
will be intentional (making $;5$ unfortunate, but $;4I'(A&.7<(6;$ quite reasonable).

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 25 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

2. Use frames as name spaces. While frames are not name spaces, contextual lookup can be used to help the situation.
Using $<46)(6D)<4.($ can provide more information than $)<4.($.
3. Name library imports with $7%&8$. It is good hygiene to import libraries using $F--7%&8$9$:6-;$%&89F--$ as if there is a
collision, the values will be the same anyway.
4. Use lookup traps when needed. If lookup should stop beyond a certain point, define the name to $b5%%$ to stop lookup
from continuing. In templates, if the value needs to be provided or the name is common (e.g., $'4;($ or $('48%(O$) use the
$s(M5&6(O$ definition to trap lookup.

For a good reflection on naming, read What's in a Name from Jane Street Tech Blog.

Patterns

In all languages, having common design patterns that introduce intent are important and this is especially true in languages
that are more flexible, since they serve the added duty of communicating intent.

Self-Rendering Items
If a list of items is generated, it can be useful to give each an attribute that renders the result. The result can then be
accumulated from this attribute.

46I7A;<%$9$R(;<%4A($G
$$'4;($9$s(M5&6(O
$$N4%5($9$s(M5&6(O
$$)<(.$9$VccV$d$'4;($d$V$V$d$N4%5(
Q
)E&A.=7A;<%$9$R(;<%4A($G
$$'4;($9$s(M5&6(O
$$4.A&N($9$R65(
$$)<(.$9$@F$4.A&N($R=('$VccV$d$'4;($Y%)($VV
Q
8&'46C$9$VF--V
46I)$9$G
$$&'<5A$9$46I7A;<%$G$'4;($9$V&'<5AV$$N4%5($9$V}>&'<5ADAaAV$Q
$$.-;<6())&-'$9$46I7A;<%$G$'4;($9$V.V$$N4%5($9$1$Q
$$%-I$9$)E&A.=7A;<%$G$'4;($9$V%-IV$Q
Q
46I7)A6$9$:-6$46I$9$46I)$s(O5.($4..$d$V$V$d$46ID)<(.$P&A=$4..$9$8&'46C

This will allow each argument to choose how to render itself as a string and provide a uniform way to aggregate the results,
free of the rendering logic itself. It is convention to use $)<(.$ (i.e., specification) or $N4%5($ as the name for rendered results.

Notice that $)E&A.=7A;<%$ has a sane default for $4.A&N($. Since users can always override, it is best to specify a default if one
is reasonable.

Modifiable Inputs
In the previous example, an argument list is created for an executable binary. The problem with this design is that it becomes
impossible to modify. It would be better to keep it as a template:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 26 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

F--7A;<%$9$R(;<%4A(
$$46I7A;<%$9$R(;<%4A($G
$$$$'4;($9$s(M5&6(O
$$$$N4%5($9$s(M5&6(O
$$$$)<(.$9$VccV$d$'4;($d$V$V$d$N4%5(
$$Q
$$)E&A.=7A;<%$9$R(;<%4A($G
$$$$'4;($9$s(M5&6(O
$$$$4.A&N($9$R65(
$$$$)<(.$9$@F$4.A&N($R=('$VccV$d$'4;($Y%)($VV
$$Q
$$8&'46C$9$VF--V
$$46I)$9$R(;<%4A($G
$$$$&'<5A$9$R(;<%4A($46I7A;<%$G$'4;($9$V&'<5AV$$N4%5($9$V}>&'<5ADAaAV$Q
$$$$.-;<6())&-'$9$R(;<%4A($46I7A;<%$G$'4;($9$V.V$$N4%5($9$1$Q
$$$$%-I$9$R(;<%4A($)E&A.=7A;<%$G$'4;($9$V%-IV$Q
$$Q
$$46I7)A6$9$:-6$46I$9$46I)$GQ$s(O5.($4..$d$V$V$d$*46I$GQ/D)<(.$P&A=$4..$9$8&'46C
Q
F--7O(N(%$9$F--7A;<%$G
$$$8&'46C$9$VF--c'&I=A%CV
$$$46I)$`9$G
$$$$$%-I$`9$G$N4%5($9$:4%)($Q
$$$Q
Q

Now, frames inheriting from $F--7A;<%$ can easily change the $46I)$.

The attribute names, if useful, can be included in the template instantiation.

46I7A;<%$9$R(;<%4A($G
$$'4;($9$z)(O
$$N4%5($9$s(M5&6(O
$$)<(.$9$VccV$d$'4;($d$V$V$d$N4%5(
Q
8&'46C$9$VF--V
46I)$9$R(;<%4A($G
$$&'<5A$9$R(;<%4A($46I7A;<%$G$N4%5($9$V}>&'<5ADAaAV$Q
$$.-;<6())&-'$9$R(;<%4A($46I7A;<%$G$N4%5($9$1$Q
Q
46I7)A6$9$:-6$46I$9$46I)$GQT$'4;($9$b4;(
$$s(O5.($4..$d$V$V$d$*46I$GQ/D)<(.
$$P&A=$4..$9$8&'46C

Enabled Items
Since there can be logic to decide if an item should be included or not, it is tempting to write code as follows:

$a$9$@F$C$j$"$R=('$R(;<%4A($47A;<%$G$4$9$+$Q$Y%)($b5%%

And then include a null check. There are two problems with this approach: the condition cannot be modified and once the
value has been replaced with null, it becomes difficult to override $a$, since a null check must be performed every time.

The solution is to add an $('48%(O$ attribute:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 27 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

$a$9$R(;<%4A($47A;<%$G
$$$4$9$+
$$$('48%(O$9$C$j$"
$Q

This means that the $`9$ attribute definition can always be used. In sequence, one could do the following in an inheriting
template:

$a$`9$G$('48%(O$9$:4%)($Q

Although $a$ is now permanently disabled, in an inheriting template, the following is still legal:

$a$`9$G$4$9$0$Q

This also allows the logic to be extended in more complex ways:

$a$`9$G$('48%(O$`-%O7('48%(O9$-%O7('48%(O$dd$O4A484)(7.-''(.A&-'D('48%(O$Q

In the case where a collection of items is used, this can be trivial to work with using a $P=(6($ clause:

46I)$9$R(;<%4A($G
$$&'<5A$9$R(;<%4A($46I7A;<%$G$'4;($9$V&'<5AV$$N4%5($9$V}>&'<5ADAaAV$Q
$$.-;<6())&-'$9$R(;<%4A($46I7A;<%$G$'4;($9$V.V$$N4%5($9$1$Q
$$%-I$9$R(;<%4A($)E&A.=7A;<%$G$'4;($9$V%-IV$$N4%5($9$R65($Q
Q
46I)7F64;()$9$:-6$46I$9$46I)$GQ$u(%(.A$46I$GQ
46I)7)A6$9$:-6$46I$9$46I)7F64;()$P=(6($46ID('48%(O$s(O5.($4..$d$V$V$d$46ID)<(.$P&A=$4..$9$VV

Flexible Rendering
This uses frame re-parenting to create multiple ways of rendering the same data:

E(4A=(6$9$R(;<%4A($G
$$A-6-'A-$9$O4A47A;<%$G$.&AC$9$VR-6-'A-V$$A(;<(64A56($9$+"$$=5;O&AC$9$,!$Q
$$E4A(6%--$9$O4A47A;<%$G$.&AC$9$VP4A(6%--V$$A(;<(64A56($9$+Z$$=5;O&AC$9$#m$Q
$$-AA4E4$9$O4A47A;<%$G$.&AC$9$VUAA4E4V$$A(;<(64A56($9$++$$=5;O&AC$9$#1$Q
Q
a;%$9$G
$$$O4A47A;<%$9$R(;<%4A($G
$$$$$)<(.$9$Vi.&ACji'4;(jt*.&AC/i>'4;(jiA(;<(64A56(jt*A(;<(64A56(/i>A(;<(64A56(ji>.&ACjV
$$$Q
$$$E(4A=(67O4A4$9$E(4A=(6$GQ
$$$)A6$9$ViE(4A=(6jV$d$*:-6$.&AC$9$E(4A=(67O4A4$s(O5.($4..$d$.&ACD)<(.$P&A=$4..$9$VV/$d$Vi>E(4A=(6jV
Q
A(aA$9$G
$$$O4A47A;<%$9$R(;<%4A($G
$$$$$)<(.$9$Vt*.&AC/tAt*A(;<(64A56(/tAt*=5;&O&AC/V
$$$Q
$$$E(4A=(67O4A4$9$E(4A=(6$GQ
$$$)A6$9$:-6$.&AC$9$E(4A=(67O4A4$s(O5.($4..$d$Vt'V$d$.&ACD)<(.$P&A=$4..$9$VH&ACtAR(;<tAf5;V
Q

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 28 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Here, the data is specified separate and the renders are provided as a template allowing different parts of the program to use
different rendering methods.

Multi-part Rendering
While $)<(.$ or $N4%5($ attributes are extremely useful, sometimes, it can be helpful to have more than one. Consider
generating C code: there need to be prototypes and implementations for each function.

.7F5'.A&-'7A;<%$9$R(;<%4A($G
$$)&I'4A56($9$s(M5&6(O
$$8-OC$9$s(M5&6(O
$$<6-A-AC<(7)<(.$9$)&I'4A56($d$V~t'V
$$&;<%(;('A4A&-'7)<(.$9$)&I'4A56($d$VGt'V$d$8-OC$d$Vt'Qt'V
Q
F5'.A&-')$9$DDD
)&I'4A56()$9$:-6$F5'.A&-'$9$F5'.A&-')$s(O5.($4..$d$F5'.A&-'D<6-A-AC<(7)<(.$P&A=$4..$9$VV
&;<%(;('A4A&-')$9$:-6$F5'.A&-'$9$F5'.A&-')$s(O5.($4..$d$F5'.A&-'D&;<%(;('A4A&-'7)<(.$P&A=$4..$9$VV
.7F&%($9$)&I'4A56()$d$Vt'V$d$&;<%(;('A4A&-')

Contextual Accumulation
There are situations where it is desirable to have an accumulator that is not common to all cases. For instance, suppose
Python code was being generated and the indentation must be correct:

<CA=-'7)A;A$9$R(;<%4A($G$%&'($9$s(M5&6(O$$)<(.$9$&'O('A$d$%&'($Q
<CA=-'7I6-5<$9$R(;<%4A($G
$$)A4A(;('A)$9$s(M5&6(O
$$)<(.$9$:-6$)A4A(;('A$9$)A4A(;('A)$s(O5.($4..$d$)A4A(;('AD)<(.$d$Vt'V$P&A=$4..$9$VV
Q
<CA=-'78%-.X$9$R(;<%4A($G
$$%&'($9$s(M5&6(O
$$)A4A(;('A)$9$s(M5&6(O

$$<46('A7&'O('A$9$w--X5<$&'O('A$@'$H-'A4&'(6
$$&'O('A$9$<46('A7&'O('A$d$VtAV
$$)<(.$9$:-6$)A4A(;('A$9$)A4A(;('A)
$$$$s(O5.($4..$d$)A4A(;('AD)<(.$d$Vt'V
$$$$P&A=$4..$9$*<46('A7&'O('A$d$%&'($d$Vt'V/
Q
&'O('A$9$VV

These templates can now be nested and the resulting $)<(.$ will have correct indentation. Groups here, are collections of
statements at the same indentation level, so any statement or block inside will continue contextual lookup until it finds
$&'O('A$. Each block takes the existing $&'O('A$ and then adds another tab, making all of the statements contained within be
indented.

Finally, the $&'O('A$ definition is an contextual lookup trap. If the user of these templates did not define an $&'O('A$ value at
the top level, contextual lookup would continue until it found this one.

The following would produce correctly indented, if not pointless, Python:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 29 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

A64')F-6;7N46$9$R(;<%4A($<CA=-'7I6-5<$G
$$$$N46$9$z)(O
$$$$)A4A(;('A)$9$K
$$$$$$$$<CA=-'7)A;A$G$%&'($9$Vt*N46/$k$846*t*N46//V$QT
$$$$$$$$<CA=-'78%-.X$G
$$$$$$$$$$$$%&'($9$V&F$t*N46/$i$!Z9V
$$$$$$$$$$$$)A4A(;('A)$9$K
$$$$$$$$$$$$$$$$<CA=-'7)A;A$G$%&'($9$V6(A56'$t*N46/V$Q
$$$$$$$$$$$$L
$$$$$$$$Q
$$$$L
Q
<C.-O($9$<CA=-'7I6-5<$G
$$$$)A4A(;('A)$9$K
$$$$$$$$<CA=-'78%-.X$G
$$$$$$$$$$$$%&'($9$VO(F$F--*a/9V
$$$$$$$$$$$$)A4A(;('A)$9$K
$$$$$$$$$$$$$$$$<CA=-'7)A;A$G$%&'($9$V6(A56'$+$g$aV$Q
$$$$$$$$$$$$L
$$$$$$$$QT
$$$$$$$$<CA=-'78%-.X$G
$$$$$$$$$$$$%&'($9$VO(F$F--\*a/9V
$$$$$$$$$$$$)A4A(;('A)$9$K
$$$$$$$$$$$$$$$$A64')F-6;7N46$G$N46$9$VaV$QT
$$$$$$$$$$$$$$$$<CA=-'7)A;A$G$%&'($9$V6(A56'$+$g$aV$Q
$$$$$$$$$$$$L
$$$$$$$$$Q
$$$$$L
$Q

In most other languages, this effect would be achieved by passing the indentation value as a parameter to every function
(plumbing) while Flabbergast can use contextual lookup to do the heavy lifting. It's also unusual to pass the value rather than
a proxy in other languages; for example, most programmers would pass an indentation number rather than the indentation
prefix.

Layered Overriding
In some cases, it is desirable to combine templates. There is no direct template merge operation, but is is possible to create a
mixin that extends a template. For instance:

47A;<%$9$R(;<%4A($G$a$9$+$$C$9$m$Q
87A;<%$9$R(;<%4A($47A;<%$G$v$9$a$`$C$Q

Here, $87A;<%$ extends $47A;<%$. If the changes that $87A;<%$ are general, it might be nice to have a higher-order way to apply
those changes to any template, not only $47A;<%$. This could be accomplished in the following way:

87&F&(6$9$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$v$9$a$`$C$Q$Q
47A;<%$9$R(;<%4A($G$a$9$+$$C$9$m$Q
87A;<%$9$87&F&(6*84)($9$47A;<%/

The $87&F&(6$ function-like template can apply the same changes to any desired template; it is a mixin, capable of extending
the behaviour of a template. The overriding mixins can be layered on top of one another:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 30 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

-N(66&O()$9$K
$$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$a$9$m$Q$QT
$$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$C$9$+$Q$QT
$$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$v$9$\$Q$Q
L
F--7A;<%$9$R(;<%4A($G$4$9$!$Q
O(6&N(O7A;<%$9
$$:-6$-N(66&O($9$-N(66&O()
$$s(O5.($-N(66&O(*84)($9$A;<%/
$$P&A=$A;<%$9$F--7A;<%
F64;($9$O(6&N(O7A;<%$G$Q

Here $O(6&N(O7A;<%$ is the combination of all the layered overrides in the $-N(66&O()$ frame. It's also possible to compose two
overriding mixins:

47&F&(6$9$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$a$9$\$g$C$Q$Q
87&F&(6$9$R(;<%4A($G$84)($9$s(M5&6(O$$N4%5($9$R(;<%4A($84)($G$v$9$a$`$C$Q$Q
487&F&(6$9$R(;<%4A($47&F&(6$G$N4%5($`-6&I&'4%9$87&F&(6*84)($9$-6&I&'4%/$Q

This will compose $47&F&(6$ and $87&F&(6$ into $487&F&(6$.

The Up-Down Problem


Many rendering problems have this conflicting nature: containers have a limit on size, but also need their sized to be
determined by their contents. This leads to a kind of dynamic system where the tree of nested boxes needs to be traversed
multiple times to determine the optimal layout. Examples of this include hierarchical layout of widgets in a GUI (e.g., Gtk+ has
its collection of size allocation methods) and text layout in document (e.g., line breaking and spacing in LaTeX).

Flabbergast can't actually make the problem easier to solve, but it can make it easier to define. In procedural and functional
languages, the state information from each step of the rendering process must be explicitly managed. Flabbergast can use
lookup to automatically unwind the dependency order of the operations given the hierarchy of widgets. If circular evaluation
occurs, then the problem is specified in a way that could only work with iterative refinement.

Consider something like:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 31 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

A(aA78-a$9$R(;<%4A($G
$$$$A(aA$9$s(M5&6(O
$$$$E&OA=$9$s(M5&6(O
$$$$=(&I=A$9$s(M5&6(O
$$$$?$Ya<%&.&A%C$O(F&'($-56$;&'&;5;)$A-$8($<4))(O$5<D
$$$$;&'7E&OA=$9$"$$;&'7=(&I=A$9$!
$$$$<6(F(66(O7E&OA=$9$!Z
$$$$?$f(6(T$-56$<6(F(66(O$=(&I=A$*E=&.=$E($<4))$5</$&)$O(F&'(O$&'$A(6;)$-F
$$$$?$-56$E&OA=T$E=&.=$&)$<4))(O$O-E'D$R=&)$;&I=A$6()5%A$&'$.&6.5%46
$$$$?$(N4%54A&-'$O(<('O&'I$-'$A=($&;<%(;('A4A&-'$-F$-56$.-'A4&'(6D
$$$$<6(F(66(O7=(&I=A$9$w('IA=$A(aA$g$!D"$>$E&OA=
$$$$N4%5($9$?$s('O(6$-5A<5A$5)&'I$E&OA=$4'O$=(&I=A
Q
F4'.C78-6O(6$9$R(;<%4A($G
$$$$.=&%O$9$s(M5&6(O
$$$$E&OA=$9$s(M5&6(O
$$$$=(&I=A$9$s(M5&6(O
$$$$?$P($('F-6.($E=4A$-56$<46('A$F-6.(O$-'$5)$-'A-$-56$.=&%O$E&OI(AD$*_-E'/
$$$$(a<7.=&%O$9$.=&%O$G
$$$$$$$$E&OA=$9$w--X5<$E&OA=$@'$H-'A4&'(6$c$!
$$$$$$$$=(&I=A$9$w--X5<$=(&I=A$@'$H-'A4&'(6$c$!
$$$$Q
$$$$?$P($)(A$-56$]5<^$N4%5()$84)(O$-'$-56$.=&%OD
$$$$;&'7E&OA=$9$(a<7.=&%OD;&'7E&OA=$`$!
$$$$;&'7=(&I=A$9$(a<7.=&%OD;&'7=(&I=A$`$!
$$$$<6(F(66(O7E&OA=$9$(a<7.=&%OD<6(F(66(O7E&OA=$`$!
$$$$<6(F(66(O7=(&I=A$9$(a<7.=&%OD<6(F(66(O7=(&I=A$`$!
$$$$N4%5($9$?$s('O(6$-5A<5A$5)&'I$E&OA=T$=(&I=AT$4'O$(a<7.=&%ODN4%5(
Q
N(6A&.4%78-a$9$R(;<%4A($G
$$$$.=&%O6('$9$s(M5&6(O
$$$$E&OA=$9$s(M5&6(O
$$$$=(&I=A$9$s(M5&6(O
$$$$.=&%O7=(&I=A$9$=(&I=A$>$*:-6$.$9$.=&%O6('$s(O5.($4..$`$!$P&A=$4..$9$Z/
$$$$(a<7.=&%O6('$9$:-6$.$9$.=&%O6('$u(%(.A$.$G$E&OA=$9$_6-<$$=(&I=A$9$w--X5<$.=&%O7=(&I=A$@'$H-'A4&'(6$Q
$$$$?$R=($;4a&;5;$-F$A=($;&'&;5;$E&OA=$-F$A=($.=&%O6('D
$$$$;&'7E&OA=$9$:-6$.$9$(a<7.=&%O6('$s(O5.($@F$.D;&'7E&OA=$j$4..$R=('$.D;&'7E&OA=$Y%)($4..$P&A=$4..$9$Z
$$$$;&'7=(&I=A$9$:-6$.$9$(a<7.=&%O6('$s(O5.($.D;&'7=(&I=A$`$4..$P&A=$4..$9$Z
$$$$?$R=($;4a&;5;$-F$A=($<6(F(66(O$E&OA=$-F$A=($.=&%O6('D
$$$$<6(F(66(O7E&OA=$9
$$$$$$:-6$.$9$(a<7.=&%O6('
$$$$$$$$s(O5.($@F$.D<6(F(66(O7E&OA=$j$4..$R=('$.D<6(F(66(O7E&OA=$Y%)($4..
$$$$$$$$P&A=$4..$9$Z
$$$$<6(F(66(O7=(&I=A$9$:-6$.$9$(a<7.=&%O6('$s(O5.($.D<6(F(66(O7=(&I=A$`$4..$P&A=$4..$9$Z
$$$$N4%5($9$?$s('O(6$-5A<5A$5)&'I$(a<7.=&%O6('q)$N4%5()
Q

The most interesting part of this example is $A(aA78-aD<6(F(66(O7=(&I=A$. It might result in circular evaluation. It also might
not. The determining factors will be how the containers are implemented and the preferred dimensions of its siblings. This is
somewhat metastable: If a text box is placed inside a vertical box (or inside a fancy border placed in a vertical box) the
answer will be stably produced. In a horizontal box (not shown), it would almost certainly be disastrous circular evaluation.
However, there are situations where it might still work depending on the exact properties of the container's layout algorithm.

The fact that the behaviour is not universally consistent is both good and bad. In the abstract, the problem is framed this way
and it makes sense: the optimal layout might not exist depending on the desired composition and the solution would be to
insert extra nodes into the rendering tree to capture the intended output (e.g., LaTeX's $;&'&<4I($ environment). However,
circular evaluation is not the most helpful error. To achieve this in a traditional language would be much more complicated;

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 32 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

the would have to be many passes and widgets would need a way to defer their decision until the next pass. Adding a new
widget which requires extra information or passes would involve invasive changes to the render (see the expression
problem). The Flabbergast interpreter is essentially dynamically determining the order in which to do the passes from the
implied dependencies.

The Standard Library


Because Flabbergast is meant to render data, it has a rather lean standard library. Most languages have the following major
elements in their standard libraries:

data structures. These are rather unnecessary once frames have been accepted as the one true data structure.
search and sort algorithms. These are built into the language via the fricasse expression.
I/O. This is highly discouraged as configurations should be hermetic and the controlling program may have security
reasons to restrict access to the world. Since there is no way to control the order of operations, output that cause side-
effects in the program is discouraged. In particular, if writing is permitted, should it happen immediately on evaluation or
after success of the whole program (i.e., can a program which produces an error still write).
files. Traditional file I/O has too much state to be practical. The best compromise would be operations to read and
write whole files. The write issue still applies.
GUIs. This is entirely mutable state.
databases. Read-only queries of databases are probably reasonable as the results can be converted to frames.
Writing can also be done transactionally, dependent on the success of the whole program.
network. Again, this is entirely mutable state. It would certainly be possible to do read-only network access,
however, the semantics surrounding network failures is unclear. Suppose an HTTP GET is available: what errors
should be handled by the program? 404? 403? 500? non-existent domain? Any can be argued, but the question is:
which represents the failure of the program and which represent the failure of the network and, most importantly,
what is the correct behaviour of the program when an error of any kind occurs?
threading. Generally, threading control is only needed so that data structures and I/O can be done safely. Since both of
those are handled outside the language, threading should be too.
string manipulation. Yuck. String manipulation is the source of all computational suffering. Embrace the frames.
regular expressions and parsing. Ignoring that parsing is usually absent, generally, this is done on the strings read from
files.
mathematics. Computation is good!
generating XML, JSON, and other formats to be read by the programs being configured.

The Flabbergast libraries look like they do to avoid I/O and minimise the ensuing insanity.

There are platform specific libraries, which end in $&'A(6-<$, to provide access to the underlying libraries. Do not access these
libraries directly. Instead, using the corresponding platform-independent library (e.g., $5A&%)$ rather than $5A&%)&'A(6-<$).
These libraries enhance the functionality of these base libraries, but the originals may still be visible in stack traces; consider
them an implementation detail.

Complete, up-to-date documentation is available on the Flabbergast Documentation site.

General Utilities ((%<=-;'<%>()

This library is a collection of convenience function-like templates. It has several broad categories of functions:

aggregation functions: $4%%$, $4'C$, $.-5'A$, $F&6)A$, $%4)A$, $;4a$, $;&'$, $<6-O5.A$, $)A67.-'.4A$, $)5;$
filtering functions: $('48%(O$, $'-'7'5%%$
precision formatting: $F%-4A7A-7)A6$ $&'A7A-7)A6$,

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 33 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Unicode manipulation: $&'A7A-7.=46$, $)A67.4A(I-6&()$, $)A67.-O(<-&'A)$


general string manipulation : $)A67().4<($, $)A67F&'O$, $)A67%-E(67.4)($, $)A67<4O$, $)A676(<%4.($, $)A67)%&.($,
$)A675<<(67.4)($, $)A67A6&;$

string analysis: $)A67<6(F&a(O$ (check for prefix), $)A67)5FF&a(O$ (check for suffix), $)A675AF17%('IA=$
parsing: $<46)(7F%-4A$, $<46)(7&'A$
frame manipulation: $F64;($, $-67O(F45%A$, $&'A7A-7-6O&'4%$, $&)7%&)A$ (check if a frame has auto-generated attribute
names)

Many of these functions have a $7%&)A$ variant. In the list variant, the output is a frame with each of the arguments treated
separately (e.g., $)A675AF17%('IA=7%&)A*VE=4AVT$VV/$ returns $K$mT$\$L$) while the non-list variant will return either an
aggregation of the results of the first (e.g., $)A675AF17%('IA=*VE=4AVT$VV/$ returns $#$).

There are also several $&F&(6$ function-like templates. These are higher-order templates: they transform the output of a
function-like template. For instance, $)5;&F&(6$ converts a function-like template that returns a list of numbers into one that
returns a sum. The $)5;$ function-like template is the $&O('A&AC$ function-like template transformed by the $)5;&F&(6$.
Similarly, the $)A675AF17%('IA=$ is also made by $)5;&F&(6$ applied to $)A675AF17%('IA=7%&)A$.

There is also a good example of using lookup to do useful work: $)A67.4A(I-6&()$. This function-like template takes a string
and returns the Unicode category for each character in the string. The categories are found by lookup. The
$)A67.4A(I-6&()7)<(.$ function converts them into the two letter names used in the Unicode specification. This function can
be re-purposed though; for instance, creating an $&)7O&I&A$ check could be done by amending the template and setting
$'5;8(67O(.&;4%$ to true, and all the other categories to false.

The $)A67().4<($ and corresponding $)A67A64')F-6;$ templates allow escaping a string for output. To do so, first, create a
frame that contains all the transformations to be performed, then pass this frame and the strings to be escaped to
$)A67().4<($ to produce an escaped version of the input. There are two kinds of transformation supported: $.=467A;<%$
transforms a single character to an escaped version (e.g., & ! $d4;<~$ or " ! $tV$) and $64'I(7A;<%$ converts characters in a
range into a numeric escape (e.g., ! $xH+xB3$ or ! $t5ZZY3$). The escaping will preferentially choose a character
transformation to a range transformation. Ranges must not overlap.

Currently, Flabbergast lacks a documentation generator, so the best information is the source comments.

Rendering ((%<=-2"78"2()

This library converts frames in to other formats, including INI, JSON, Python, XML, and YAML. In short, the library provides
templates such that a frame can be rendered to output formats. The exact semantics are different for each format, but, in
general, the templates are composed into the desired structure providing the hierarchy and the library generates a string
containing the output file. Escaping is handled automatically.

Mathematics ((%<=-#&'?()

The mathematics library contains all the usual functions for:

exponentiation and logarithms: $%-I$, $<-E(6$


trigonometry ($.&6.%($ and $=C<(68-%4$): $46..-)$, $46.)&'$, $46.A4'$, $.-)$, $)&'$, $A4'$
rounding: $48)-%5A($, $.(&%&'I$, $F%--6$, $6-5'O$
constants: $'4A564%$, $<&$, $A45$

Much like $%&895A&%)$, there are $7%&)A$ variants of these. The trigonometric functions are a bit unique: by setting
$4'I%(75'&A$, the units used for angles can be changed between degrees, gradians, radians, and turns; the default is radians.

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 34 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

Relational Database Access ((%<=->@%( and (>@%-()

Flabbergast provides access to SQL-like databases available through JDBC and ADO.NET providers. Fundamentally, this
system exists in two parts: $%&89)M%$ provides mechanisms for composing queries and the $)M%9$ URIs connect to databases.
When accessing a URI, for instance, $)M%9)M%&A(9F--D)M%&A($, Flabbergast scans the database metadata and provides that
as a structure of frames. The $%&89)M%$ library can then be used to compose a query, checking that the query is valid given
the format of the database, and converts the results to a list of matching rows. This format is easily ingested by $:-6$Y4.=$.

Not all SQL data types can be converted to Flabbergast. The templates in the library smooth out the differences between
different data source providers. This means that some functionality might not be available for all different database types.

)M%7%&8$9$:6-;$%&89)M%
6()5%A)$9$)M%7%&8D6(A6&(N($G
$$$)-56.($9$:6-;$)M%9<-)AI6()M%9<IO8D(a4;<%(D.-;>=5;4'76()-56.()
$$$.-%5;')$9$G
$$$$'4;($9$(a<6D)A67J-&'$G$46I)$9$K$.-%5;'D(;<%-C((DF&6)A7'4;(T$V$VT$.-%5;'D(;<%-C((D%4)A7'4;($L$Q
$$$$)4%46C$9$.-%5;'D<4C6-%%D)4%46C
$$Q
$$E=(6($9$K$(a<6D(M54%$G$%(FA$9$.-%5;'D(;<%-C((D(;<7&O$$6&I=A$9$.-%5;'D<4C6-%%D(;<7&O$Q$L
Q
6(<-6A$9
$$:-6$Y4.=$6()5%ADN4%5(
$$$$s(O5.($4..$d$Vt*'4;(/$;4X()$yt*)4%46C/$<(6$C(46Dt'V
$$$$P&A=$4..$9$VV

This is not intended as a general interface to relational databases. In particular, the column and table names really need to be
Flabbergast identifiers, which is not generally true. The complexity of the queries is also limited since the system tries to work
on multiple databases seamlessly. It might be best to create a view in a compatible format.

Flabbergast has a standard format for database connection strings, due to the fact that no one else does. That format is:
$)M%9i<6-N&O(6j9iF&%($<4A=j$ or $)M%9i<6-N&O(6j9Ki5)(6jK9i<4))E-6OjLL=-)AK9i<-6AjL>i.4A4%-Ij$ optionally suffixed by a
$e$ and various ampersand-separated key-value pairs. The format used depends on the database (e.g., SQLite uses the
former, PostgreSQL uses the latter). Additional libraries are required for each different database provider.

For a list of supported databases and their options, view $;4'$F%488(6I4)A7)M%$. Currently, only a handful of databases are
supported. Patches for new databases are welcome.

Environment Variables (("7A-()

Current environment variables may be accessed with $('N9$ URIs. For instance, to access the current path, use $('N9WBRf$.

External Files ((B'$-(, (B'$>-(, (B<%"-(, and (2">-()

These read data from an external file and provide a $3&'$ value containing the contents of the file. The $6()9$ URI gathers
data from files intended to be resources. It searches the same paths as $%&89$ URIs for a matching file name.

HTTP Files ((?''$-(, (?''$>-()

These read data from a web URL and provide a frame with two attributes: $O4A4$ containing the contents of the file, as a $3&'$
value; $.-'A('A7AC<($ containing the content-type string provided by the server.

Parsing ((%<=-$&2>"()

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 35 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

A mirror to $%&896('O(6$, this contains $<46)(7J)-'$, which parses a string containing JSON and produces templates
compatible with $%&896('O(6$. It will produce a template of the form:

$R(;<%4A($G
$$$J)-'$9$z)(O
$$$J)-'76--A$9$i.-'A('A)$-F$F&%(j
$Q

The structure of the JSON file is preserved using template instantiations: $J)-'D-8J(.A$, $J)-'D%&)A$, and $J)-'D).4%46$.
These mirror exactly the format in $%&896('O(6$. This means a JSON file can be re-encoded using:

$6('O(67%&8$9$:6-;$%&896('O(6
$<46)(7%&8$9$:6-;$%&89<46)(
$F--$9$<46)(7%&8D<46)(7J)-'*J)-'7O4A4/$G
$$$$J)-'$9$6('O(67%&8DJ)-'
$Q
$N4%5($9$F--DJ)-'76--ADJ)-'7N4%5(

It is reasonable to supply other templates to convert the JSON input to something else. For instance, these transform it in to
Flabbergast objects, assuming all the names are Flabbergast-compatible:

$F--$9$<46)(7%&8D<46)(7J)-'*J)-'7O4A4/$G
$$$$J)-'$9$G
$$$$$$%&)A$9$R(;<%4A($G
$$$$$$$$N4%5($9$.=&%O6('
$$$$$$Q
$$$$$$).4%46$9$R(;<%4A($G
$$$$$$$$N4%5($9$46I
$$$$$$Q
$$$$$$-8J(.A$9$R(;<%4A($G
$$$$$$$$N4%5($9$:-6$.=&%O$9$.=&%O6('$u(%(.A$.=&%ODJ)-'7'4;($9$.=&%ODN4%5(
$$$$$$Q
$$$$Q
$Q
$F%488(6I4)A7N4%5($9$F--DJ)-'76--ADN4%5(

Due to contextual lookup, it is possible to define templates inside to change the behaviour at lower levels:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 36 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

$F--$9$<46)(7%&8D<46)(7J)-'*J)-'7O4A4/$G
$$$$J)-'$9$G
$$$$$$%&)A$9$R(;<%4A($G
$$$$$$$$?$@F$A=(6($&)$4$%&)A$&'$4AA6&85A($'4;(O$]&'A(I(6)^T$.-'N(6A$4%%$A=(
$$$$$$$$?$'5;8(6)$&'$&A$A-$&'A(I(6)D
$$$$$$$$J)-'$9
$$$$$$$$$$@F$J)-'7'4;($kk$V&'A(I(6)V
$$$$$$$$$$$$R=('$G
$$$$$$$$$$$$$$).4%46$9$R(;<%4A($G
$$$$$$$$$$$$$$$$J)-'7N4%5($9$46I$R-$@'A
$$$$$$$$$$$$Q$Y%)($GQ
$$$$$$$$J)-'7N4%5($9$.=&%O6('
$$$$$$Q
$$$$$$).4%46$9$R(;<%4A($G
$$$$$$$$J)-'7N4%5($9$46I
$$$$$$Q
$$$$$$6('O(67%&8$9$:6-;$%&896('O(6
$$$$$$-8J(.A$9$R(;<%4A($G
$$$$$$$$?$R=($A6(($5'O(6$4'$4AA6&85A($'4;(O$];4I&.^$E&%%$8($.-'N(6A(O$84.X
$$$$$$$$?$A-$uUb$4)$4$)A6&'I~$A=($6()A$A-$:%488(6I4)AD
$$$$$$$$J)-'$9$@F$J)-'7'4;($kk$V;4I&.V
$$$$$$$$$$R=('$6('O(67%&8DJ)-'
$$$$$$$$$$Y%)($w--X5<$J)-'$&'$H-'A4&'(6
$$$$$$$$J)-'7N4%5($9$:-6$.=&%O$9$.=&%O6('$u(%(.A$.=&%ODJ)-'7'4;($9$.=&%ODJ)-'7N4%5(
$$$$$$Q
$$$$Q
$Q
$F%488(6I4)A7N4%5($9$F--DJ)-'76--ADJ)-'7N4%5(

Apache Aurora ((%<=-&$&5?"C&;212&()

Configures jobs for running on the Apache Aurora framework, which managers long-running jobs on Mesos.

Archives ((%<=-;7<)C&2()

Since Flabbergast only outputs a single value, it can be awkward to generate multiple files. To combat this, it supports
creating $46$-style archives, which are plain text. To do this, instantiate $46.=&N(7A;<%$ with the $46I)$ being a list of
$F&%(7A;<%$, each with $F&%(7'4;($ and $.-'A('A)$. The resulting file can then be unpacked using the UNIX $46$ program.

Permission Specifiers ((%<=-;7<)C$"2#()

Helps generate UNIX-style file permissions and format them nicely.

Cron Specifiers ((%<=-;7<)C5217()

Allows generating the time specifications in for $.6-'A48$ entries.

Automatic Documentation

Flabbergast has a built-in documentation system. Unlike, say JavaDoc, Flabbergast documentation is parsed by the compiler
and certain checks are done on it. Adding documentation goes in two places: an introduction and attribute documentation.

An introduction is associated with a whole file and appears at the top of a file:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 37 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

@'A6-O5.A&-'GGGB$%&8646C$-F$A(;<%4A()$F-6$O-&'I$5)(F5%$A=&'I)DQQQ

Before each attribute, a description of the attribute can be inserted in triple braces:

GGGR=($zsw$F-6$A=($:%488(6I4)A$<6-J(.ADQQQ
F%488(6I4)A756%$9$V=AA<9>>F%488(6I4)AD-6IV

That will continue inside literal frames and templates:

GGGB%%$A=($zsw)DQQQ
56%)$9$G
$$GGGR=($zsw$F-6$A=($:%488(6I4)A$<6-J(.ADQQQ
$$F%488(6I4)A$9$V=AA<9>>F%488(6I4)AD-6IV
$$GGGR=($zsw$F-6$A=($:%488(6I4)A$<6-J(.ADQQQ
$$I&A=58$9$V=AA<)9>>I&A=58D.-;V
Q

But it won't traverse other expressions:

GGGR=&)$E&%%$8($&'$A=($O-.5;('A4A&-'DQQQ
A=&'I&($9$@F$a$R=('$G
$GGGR=&)$E&%%$'(N(6$8($O&)<%4C(OQQQ
$)4OO'())$9$R65(
Q$Y%)($b5%%

Inside documentation, there are text formatting tags: $tY;<=GaQ$ will add emphasis to the text, and $t[-'-GaQ$ will type set it in
a fixed-width font. Hyperlinks can also be inserted using $tw&'XG=AA<9>>F%488(6I4)AD-6I>nH%&.X$A-$I-$A-$A=($:%488(6I4)A
<4I(Q$. Cross-references to other attributes can be created using $tG56%)DI&A=58Q$ or to other libraries $t:6-;G%&89aQ$.

Questions of Varying Frequency


The following answers are universally discouraging of certain ideas as these ideas are not congruent with normal Flabbergast
use. More philosophical questions are answered in FAQ.

When do I end something with (D'#$%(? How do you feel about Hungary?

I sometimes suffix attribute names that hold templates with $7A;<%$, but not always. I would love to provide some rule, but it is
one of those value judgements. In particular, there are two scenarios I see: mixed frames and meta-templates. Templates
meant to be used in function-like scenarios should never end with $7A;<%$.

In certain contexts, there is a mix of different types and suffixing templates can be helpful. For example:

A=&'I&(7A;<%$9$R(;<%4A($G$'4;($9$s(M5&6(O$Q
A=&'I&()$9$K$A=&'I&(7A;<%$G$'4;($9$y4$Q$L
'5;7A=&'I&()$9$:-6$a$9$A=&'I&()$s(O5.($4..$`$!$P&A=$4..$9$Z
%('IA=7A=&'I&()$9$:-6$a$9$A=&'I&()$s(O5.($4..$`$w('IA=$aD'4;($P&A=$4..$9$Z
A=&'I&(7.)N$9$:-6$a$9$A=&'I&()T$<-)$9$U6O&'4%$s(O5.($4..$d$*@F$<-)$j$!$R=('$VTV$Y%)($VV/$d$aD'4;($P&A=$4..$9$VV

This context has a number of unrelated items. They are of different types and meant for different purposes. Naming the
template $A=&'I&(7A;<%$ gives an indication that this is the intended template to be used by all these other $A=&'I&($

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 38 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

definitions.

The other situation that occurs relatively frequently is the meta-template. There are many of these in the compiler. It is often
useful to have a template which is never meant to be instantiated by the end user; it is simply a base on which to build more
templates. In that case, the $7A;<%$ suffix functions almost as an indicator of abstractness. For example:

&')A65.A&-'7A;<%$9$R(;<%4A($GQ
4OO7&')A65.A&-'$9$R(;<%4A($&')A65.A&-'7A;<%$G$%(FA$9$s(M5&6(O$$6&I=A$9$s(M5&6(O$Q
;5%A&<%C7&')A65.A&-'$9$R(;<%4A($&')A65.A&-'7A;<%$G$%(FA$9$s(M5&6(O$$6&I=A$9$s(M5&6(O$Q

For inheritance reasons, it will provide a place for common plumbing between all the other instructions, but it isn't meant to be
consume directly.

Hungary makes delicious food. Please do not apply it to Flabbergast.

How do I use a string as the URI in (021#(?

This is intentionally not possible. For various embedding reasons, it's important that the dependencies of a file are known
during compilation. Importing new files can lead to all kinds of misery for doing any analysis of the code, and might represent
a security problem.

If the goal is to read from a configuration specific file, then invert the inheritance structure:

I%-84%7.-'F&I$9$R(;<%4A($G
$$'4;($9$s(M5&6(O
$$;4.=&'(7&'F-$9$:6-;$V&'F-9;4.=&'(>t*'4;(/V$?$_()&6(OT$85A$5'6(4%$)C'A4a
Q
%-.4%7.-'F&I$9$I%-84%7.-'F&I$G$'4;($9$VF--V$Q

The correct refactoring is something like:

I%-84%7.-'F&I$9$R(;<%4A($G
$$;4.=&'(7&'F-$9$s(M5&6(O
Q
%-.4%7.-'F&I$9$I%-84%7.-'F&I$G
$$;4.=&'(7&'F-$9$:6-;$&'F-9;4.=&'(>F--
Q

In general, the solution is to either use contextual lookup or inheritance to find the needed data. If there is a collection of data,
then it might be useful to have a footprint. In a global library, create a template for each type of configuration:

I%-84%7.-'F&I$9$R(;<%4A($G
$$a$9$F--A<6&'AD;4.=&'(7&'F-D.<5
Q
A()A7.-'F&I$9$R(;<%4A($I%-84%7.-'F&I$G
Q

Then create a single situation-specific footprint:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 39 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

F--7F--A<6&'A$9$G
$$;4.=&'(7&'F-$9$:6-;$&'F-9;4.=&'(>F--
Q

Then for each configuration is only a marriage of footprint and template:

.-'F&I7%&8$9$:6-;$%&89.-'F&I7A(;<%4A()
F--A<6&'A$9$:6-;$%&89F--7F--A<6&'A
.-'F&I$9$.-'F&I7%&8DI%-84%7.-'F&I$G$Q

These final files tend to be rather short.

How do I create a new type?


There isn't a mechanism to create user-defined types as such. There are two reasons: what would be the look-up rules for
type names and how would one define new primitive operations? In general, there's no reason to create a new type: create a
new frame with a well-defined interface. For all typical purposes, that is as good as defining a new type. In the typical class-
based object-oriented sense, there is no guarantee that a frame will inherit the intended template, but if it has a compliant
interface, there isn't necessarily any harm.

Many languages have restricted value sets: enumerations (C, C++, Java, C#) or symbols (LISP, Ruby, SmallTalk). These are
intended to be universally comparable values that exist in some kind of special name space. Symbols are essentially strings,
so the $y$ identifier-like string is essentially the same. An enumeration-like structure can be easily made:

;C7('5;$9$:-6$a$9$Ky4T$y8T$y.L$u(%(.A$a$9$a

The value of enumerations is mostly that they are cheap to compare and use in $)E&A.=$ statements. Since none of that really
translates to Flabbergast, this isn't so pressing. Rather than have dispatch logic, put the results in the frames or templates.

Again, the way to think of this is to invert where the data is stored, rather than:

;C7('5;$9$:-6$a$9$Ky4T$y8T$y.L$u(%(.A$a$9$a
A;<%$9$R(;<%4A($G
$$$$('5;&)=$9$s(M5&6(O
$$$$'4;($9$s(M5&6(O
$$$$N4%5($9$'4;($d$V$k$V$d$*
$$$$$$$$@F$('5;&)=$kk$y4$R=('$VZV$Y%)(
$$$$$$$$@F$('5;&)=$kk$y8$R=('$V!V$Y%)(
$$$$$$$$@F$('5;&)=$kk$y.$R=('$V\V$Y%)(
$$$$$$$$Y66-6$V34O$('5;DV/
Q
a$9$A;<%$G$'4;($9$VF--V$('5;&)=$9$y4$Q

It would also be completely reasonable to provide a frame with all the needs:

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 40 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

;C7('5;$9$G
$$4$9$G$&O$9$Z$Q
$$8$9$G$&O$9$!$Q
$$.$9$G$&O$9$\$Q
Q
A;<%$9$R(;<%4A($G
$$$$('5;&)=$9$s(M5&6(O
$$$$'4;($9$s(M5&6(O
$$$$N4%5($9$'4;($d$V$k$V$d$('5;&)=D&O
Q
a$9$A;<%$G$'4;($9$VF--V$('5;&)=$9$;C7('5;D4$Q

That can be taken further by making the enumeration values as templates:

;C7('5;$9$G
$$4$9$R(;<%4A($G$N4%5($9$VZ$t*'4;(/$ZV$Q
$$8$9$R(;<%4A($G$N4%5($9$V!$t*'4;(/$ZV$Q
$$.$9$R(;<%4A($G$N4%5($9$VZ$t*'4;(/$!V$Q
Q
A;<%$9$R(;<%4A($G
$$$$('5;&)=$9$s(M5&6(O
$$$$'4;($9$s(M5&6(O
$$$$N4%5($9$'4;($d$V$k$V$d$*('5;&)=$GQ/DN4%5(
Q
a$9$A;<%$G$'4;($9$VF--V$('5;&)=$9$;C7('5;D4$Q

2017 GitHub, Inc. Terms Privacy Security Status Help Contact GitHub API Training Shop Blog About

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 41 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 42 of 43
flabbergast/flabbergast-manual.md at master flabbergast-config/flabbergast GitHub 3/28/17 11:30 AM

https://github.com/flabbergast-config/flabbergast/blob/master/flabbergast-manual.md Page 43 of 43

S-ar putea să vă placă și