Home
Composition of data structures.
Composition in this sense is building a complex data structure via the
operations of cartesian products and unions. Basically, Deft allows
the (almost) trivial creation of complex data structures, and the
manipulation of the structure (and data, of course). Deft's internal
data structure is represented by a single instance of a first normal
table. That Deft is able to do composition is a hopefully obvious
consequence of relational operations and normal form.
Deft currently relies on SQL for data storage, however, SQL has
limited abilities which prevent SQL from supplanting Deft as far as
data structure. Due to the limits of SQL, creating and managing a
Deft-like unitary table is quite difficult. If you consider basic
(standard) SQL, then the act of creating a unified table would require
that all the SQL queries necessary to build the table would be in a
single query (as subqueries).
Deft has scalar variables in the (more or less) normal sense. Deft
does not have (nor needs) arrays, lists, hashes, user created
"structs/classes", or combinations of these structures. Deft has a
single, implicit, first normal table. We distinguish it with the
special name "the Stream" when speaking about it. The Stream is never
referred to since (like mass or gravity) it is fundamental (and
automatic) to the fabric of Deft. It is well established that any
arbitrary data structure can be represented in first normal form. In
order to understand Deft, you should easily understand why (if not,
please contact the authors of Deft so we can write applicable
tutorials). What is not so obvious is that describing the complex
structure only takes a small number of functions (dcc(), desc(),
duc()). The Stream (being a first normal table) is powerful enough for
most uses without additional structure imputed on it. When extra
complexity is necessary (e.g. when you need a tree), you only need a
single, fairly simple function call. Additionally, several different
tree structures are just as easily imputed onto the Stream.
Scalar variables and the execution model.
Each line of Deft is run in a declarative manner. Each line of code
will be applied to each row in the Stream. Scalar variables are
columns from the Stream. In order to illuminate the execution model
you should know about two internal functions: unwind() and
rewind(). Unwind reads a record from the Stream. Rewind writes a
record back into the Stream. (The actual implementation involves a
streaming queue, and is akin to a pop/unshift.) The execution model
for a single line of scalar Deft code:
$my_counter++;
is
while(unwind())
{
$my_counter++;
rewind();
}
In other words, unwind a row, increment the value in the column
$my_counter, and then rewind the row. Some of you may recognize that
many optimizations of unwind/rewind are possible.
The way Deft implements composition of data structures allows (almost)
trivial creation of structure. A column containing the structure
information is a column of data like any other column (strucutre data
is first class data). dcc() creates a structure column. A new column
is created that contains an ordering, with a "where" clause. Existing
columns aren't changed. dcc() happens to be used almost exclusively
for rendering web pages. To give a concrete example, a template with a
loop would require a list of hashes with HTML::Template. The same
template in Deft requires only a single dcc() call (Deft has a
powerful built-in template engine). Unlike HTML::Template where the
programmer is required to build the list of hashes, in Deft the "list
of hash" equivalent structure is merely imputed onto the Stream. The
more complex the problem, the greater the advantage of composing
structure. Any HTML::Template with a doubly nested loop requires "list
of hashes of lists of hashes". Parts of the template outside the loops
will require a separate hash. Traditional programming quickly acquires
many data structures, all with their attendant management code. Our
example of a template with some "flat" values, values in the outer
loop and values in the inner loop requires 2 data structures. Deft
requires two dcc() calls. Deft uses two lines of code, and the data
needs no prior preparation.
Those of you who have been required to create and manage nested lists
of hashes will understand that these structures are a headache.
The traditional "list of hashes of lists of hashes" must be built to
purpose, and that structure isn't really useful for much else. If the
programmer with an n-way structure needs the same data flat, there
will be two (or more) sets of data to manage. Deft will always only
have one set of data. The traditional subroutines and associated data
structures can't easily be repurposed. Deft subroutines work on data
you care about, and ignore columns you don't care about (including
columns with imputed structure).