Introduction to QL

The other side of creating Large Text Properties such as the Default View is QL. (Pronounced "cool".) The easiest way to understand the basics is with a couple of examples.
In Text, Large Text and the Default View, we saw that this Default View:
3y2848u/d70b62568f9949b02177be011d52706c86d4fd90.png
produced this display when we applied it to Spy:
3y2848u/da2d529c9ae3779d1cc7dd9ee9937f32af6f92d3.png
What's going on here? The stuff inside the double-square-brackets is QL (which is simply short for "Querki Language"), and we call anything inside double-square-brackets a QL expression. The simplest and most common QL expression is simply naming a Property on this Thing, in which case it gets replaced with the value of that Property. So [[Notes]] becomes "Has a briefcase full of incriminating documents", because that is the value of the "Notes" Property on Spy.
So far, so good. But in the Introduction to QText, one of the illustrations showed that [[Learning Querki]] becomes Learning Querki -- that is, it becomes a link to that page. The implication is that naming a Thing that isn't a Property becomes a link to that Thing.
At this point, some of the more experienced programmers are probably doing a facepalm and saying, "Oh, God, it's all ad hoc chaos like PHP".
Actually, it's not -- it's all quite organized and consistent -- but the subtleties are deliberately hidden. We'll go into more detail in More about QL, but suffice it to say, every Thing has an internal function associated with it, named _apply(). _apply() is specifically what to do when this Thing is named in QL. By default, _apply() on Things returns a link to that Thing, and _apply() on Properties is a function that receives a Link to a Thing and produces this Property's value on that Thing. The various predefined Functions have specialized definitions of _apply(), and you can create your own global Functions by creating a Thing and adding your own version of the _apply Property, which will override the internal _apply().
Credit where credit is due: this notion of _apply() is stolen from Scala, the language that Querki itself is written in. Might as well learn from the best...
If the above is all the QL you learn, it's enough to do a lot in Querki: you can link from page to page and do simple display with just that simple construct of naming something inside double square brackets. But with a little more QL, you can get a lot fancier in your display.
(Caveat: the rest of this page is programming. It's not very complicated programming, but it would be a lie to claim otherwise. If you don't want to deal with programming, skip the rest of this page.)
Before we get into the details, some programmers may prefer the shorthand.
Putting it concisely: QL is a (mostly, for now) functional programming language, albeit a pretty idiosyncratic one. Syntactically, it is stream-oriented: you pass contexts -- essentially values with metadata -- from left to right across stages. Each stage can be understood as a function, transforming the received context into a new produced one.
QL isn't fancy, but isn't trying to be: it was written from the ground up with an eye towards being as syntactically simple as possible. In that, it is sort of like Scheme, but deliberately tries to do as much as possible left-to-right instead of doing it all with nested function calls -- my contention is that that's both easier to teach and to read. (There are function calls, and even parenthesized parameters, but you don't use them nearly as often in QL.)
In a sense, it is a domain-specific language, optimized for querying the Querki database and displaying the results -- the most central design goal was that typical expressions should be as obvious and concise as possible. However, it is completely neutral about the domain of the data -- it is a DSL in roughly the same sense that SQL is. Indeed, QL is roughly isomorphic to SQL, but uses streams and data-transformation functions instead of query declarations.

Context

The most important concept in really understanding QL is context. Each name given in QL is called a stage; the stage receives a context from the left, and produces a context to the right. That's most of what happens in QL -- passing values from left to right, transforming the context in each stage.
When we simply name a Property, like [[Notes]], what is really going on here? Every QL expression in the Default View starts out by receiving a link to the current Thing -- the page you're looking at -- as its initial context. The Notes Property then takes that context, looks up the value of Notes in it, and produces that value. When we get to the end of the expression, we turn whatever was produced at the end into QText, and put it into the display there.
So when we look at [[Notes]] on the Spy page, what's really going on is more like "Spy -> [[Notes]] -> value of Notes -> QText of the value of Notes" -- the QL expression takes the current page as its initial context, and produces some QText at the end. (The resulting QText depends on the Type of the values produced at the end; it usually makes pretty intuitive sense.)

Getting back to that example

In Text, Large Text and the Default View, we showed that this page:
3y2848u/2117307bd6c14928dbff04dddae92838406cab82.png
is actually constructed from this QL expression:
[[Game._instances ->
  _sort ->
  ""**____**: [[Owners -> _commas]]"" ->
  _bulleted]]
Now it's time to go through an explain that, bit by bit. In four lines, it shows you most of what you need to know about QL programming. (And don't fret -- it doesn't usually get more complex than this. This example is pretty typical of an interesting page that is displaying complex data.) We're going to go through it line-by-line and explain what's happening.

Stage to Stage

First, note that the first three lines end with ->, aka "arrow". This is how you connect stages together, and it means that the stage to the left of the arrow produces a context which is received by the stage on the right of the arrow. Those arrows are required, but the line breaks aren't; this same expression could be written:
[[Game._instances -> _sort -> ""**____**: [[Owners -> _commas]]"" -> _bulleted]]
I usually prefer to have one stage per line when a QL expression gets beyond two or three stages, but that's purely a matter of taste -- do what makes sense to you.

Fetching the Instances of a Model

We start out with this stage:
Game._instances
_instances is a function -- a function takes a value and transforms it in some way. _instances expects to receive a Model (technically a Link to a Model, but you don't usually need to worry about that), and produces a List of all of the Instances of that Model. So in this case, it receives the Model Game, and produces a List containing Innovation, We Didn't Playtest This at All, Red 7 and Flowerfall. Note that this list is not necessarily in any particular order.
Why isn't there an arrow? _instances is a special function that can either operate on the received context or on the defining context, which simply means a name on the left-hand side of a period. Defining context is occasionally important in QL, especially when you need to combine Things, but you can ignore it most of the time. This same line could be written
Game -> _instances
but I prefer to do it the first way, because I think it helps remind me that this QL expression is completely shrugging off the initial context (the page we're looking at) and doing its own thing.
In general, when you want a page that is some kind of query, showing the data in this Space sliced-and-diced in some fashion, you most often start with a stage using _instances like this.

Sort the results

The next stage is simply:
_sort
This receives a List, sorts it, and produces the result of that sort. The meaning of "sort" depends on the Type of the List. Most often, you use it with a List of Things like this, and it sorts them by Display Name, which is typically what you want. (You can sort by specific fields of the Things, and even do sub-sorting with multiple fields -- see the documentation on _sort for more information.)

Format the results: QText Stages

Now we get to the really complicated stage:
""**____**: [[Owners -> _commas]]""
What's going on here? The answer is that QL and QText can be nested in each other. This is really important -- it is how you do fancy queries and displays in Querki -- so let's go into that a bit.
You already know that in QText, when you surround something with double-square-brackets, that defines a QL expression. The same thing works the other way around as well: in a QL expression, double-double-quotes define some QText. Inside those double-double-quotes, you're back to the QText world -- you can put whatever text and whatever markup you like. So this stage is saying that we should pass that sorted List of Games into this QText:
**____**: [[Owners -> _commas]]
More precisely, when QL hits a QText expression like this, it goes through the received List, and passes each one separately into the QText. This is almost always what you want, because it lets you format each of those Things.

Context Display

Okay, so what is with those underscores at the beginning of the line?
**____**:
Four underscores are a convenient shorthand in QText -- they mean "display the received context here". Remember that we're passing each Game (technically, a Link to a Game) into this QText expression -- the four underscores tell the QText to put that Link here. And as we saw at the beginning of this page, a Thing displays as a link (in the HTML sense) to that Thing, using the Display Name of that Thing as the displayed text. And of course, the double-asterisks around it is QText for "boldface".
(What if you want your link to display some other text? You surround the text you want with double-underscores, like this:
[[My Link -> ""**__Go to My Link__**""]]
That's why the four underscores for the simple shorthand -- it is this pair of double-underscores, with nothing specified to display.)

Nesting Deeper

The QText stage ends with:
[[Owners -> _commas]]
That's a QL expression again, and shows that you can do this nesting as deeply as you like, going back and forth between QText and QL. Since the QText stage received a Game, that's how this QL expression inside it should be understood. It receives that Game, and then applies the Owners Property, which you'll recall is a Set of Links to the owners of this Game.

Lists with Commas

At the end of
[[Owners -> _commas]]
there is that _commas. That is a function, which takes a List or Set, and produces QText showing the values of that List or Set, comma-separated.
So putting all that together, this stage:
""**____**: [[Owners -> _commas]]""
should be understood as "for each Game in the received List, produce some QText, starting with a link to that Game, followed by a comma-separated list of the Owners of that Game".
Yes, that's a bit dense at first. But once you get the hang of reading QL and QText, it gets pretty easy to understand -- it just takes some practice.

Bullet Lists

Finally, the last stage is simply:
_bulleted
This is a lot like _commas above -- where _commas means "display this List, comma-separated", _bulleted means "display this List as a bullet list". It's purely a matter of taste, but I very frequently end my QL expressions with _bulleted -- I simply find bullet lists easier to read. (Note that _bulleted nests properly: if you put one bullet list inside another, they will display outline-style, with nested bullet lists. However, they do not currently nest properly with QText-style bullet lists, the lines that start with "*". This may get fixed at some point.)

Putting it All Together

So, we have this QL expression:
[[Game._instances ->
_sort ->
""**____**: [[Owners -> _commas]]"" ->
_bulleted]]
Taken as a whole, that can be read as, "Take all the Games, sort them, for each one display the link to it and a comma-separated list of its Owners, and show them all as a bullet list".
If you're having trouble figuring out how to approach this, read on: a bit later, we'll talk about Querki Explorer, which is an interactive QL editor. That makes it much easier to fiddle around with QL expressions, quickly trying things out until you get what you want. And for more nitty-gritty detail about QL, see More about QL under Advanced Topics.