> ## Content Index
> Fetch the complete content index at: https://dsl-consultancy.ghost.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Booleans
- URL: https://dsl-consultancy.ghost.io/booleans/
- Published: 2026-09-12T09:16:49.000Z
- Updated: 2026-09-24T08:29:31.000Z
- Author: Meinte Boersma

💡

This is post 06 in my blog series on MyFPL — see [the index/table of contents](https://codeberg.org/dslmeinte/my-fpl/src/branch/main/blogs/index.adoc?ref=dsl-consultancy.ghost.io).  
  
The code in this and previous blog posts can also be found [here, on Codeberg](https://codeberg.org/dslmeinte/my-fpl?ref=dsl-consultancy.ghost.io). Check out the repo at the commit marked “blog 06”.

In the previous blog post, we constructed a LionWeb language with the base interfaces for MyFPL: `Value`, `Literal`, `Operation`, and `Type`. But we didn’t add any concrete – i.e.: instantiable – subtypes of these interfaces yet. In this blog post, we’ll change that, and add *booleans*, meaning we’ll be adding the boolean type, boolean literals, and some boolean operations. I chose to start with the implementation of booleans (rather than integers), because we’d like to get to do some collection operations as soon as possible, and we need booleans for that.

Booleans are a bit weird, because there are only two booleans: `true` and `false`. Nevertheless, the implementation of booleans that we’ll create here forms the mold for implementing other types.

## Expanding MyFPL’s structure

First of all, let’s add a `BooleanLiteral` concept that implements the `Literal` interface, by appending the following code to the `packages/build/structure.ts` file:

```
const BooleanLiteral = factory.concept("BooleanLiteral", ConceptModifier.concrete).implementing(Literal) (1)
const { builtinsFacade } = LionWebVersions.v2023_1 (2)
const { booleanDataType } = builtinsFacade.primitiveTypes (3)
factory.property(BooleanLiteral, "value").ofType(booleanDataType) (4)
```

1. Construct a concrete *concept* named `BooleanLiteral`. This relies on importing the `ConceptModifier` enumeration from the `@lionweb/core` NPM package.
2. Destructure the `v2023_1` constant on the `LionWebVersions` object to get access to the `builtinsFacade`. This relies on importing that `LionWebVersions` object from the `@lionweb/core` NPM package.
3. Destructure the `booleanDataType` constant from `builtinsFacade.primitiveTypes`.
4. Construct a *property* named `value` on `BooleanLiteral` that holds a value of type boolean.

---

### Design choice

It might seem weird that we’re constructing a whole concept for the literal values of a type of which there are only two. One reason for this is that the boolean type is exceptional in having only two literal values: all other types will have many more values.

The alternative is that we create two concepts: `TrueBooleanLiteral`, and `FalseBooleanLiteral` — corresponding in the obvious way to `true` and `false`. We probably also want to add a `BooleanLiteral` interface, and have the literal concepts implement that.

The upside of this approach would be that these concepts don’t need a `value` property, which saves some bytes. But you would still need an instance of either of these concepts for every literal appearing in program code. So saving a couple of bytes for a boolean field on a(n instance of a) class doesn’t amount to much.

Also, to process a boolean literal named – say – `value`, we’d need to do a type comparison: `value instanceof TrueBooleanLiteral` for `true`, and `value instanceof FalseBooleanLiteral` for `false`. We really have to check both cases everywhere we might be processing a boolean, because we can’t say `value instanceof BooleanLiteral` in TypeScript — assuming `BooleanLiteral` is an interface. When we have only `BooleanLiteral` we can first check `value instanceof BooleanLiteral` and then inspect its `value`: `value.value` — much more elegant.

---

Now that we have boolean literal values, we can create some boolean operations. The obvious type/class of boolean operations is that of the *binary operation* – e.g. boolean *and* and *or* – and *boolean negation*. Let’s create a `BinaryOperation` concept:

```
const BinaryOperator = factory.enumeration("BinaryOperator") (1)
;["and", "or"].forEach((op) => factory.enumerationLiteral(BinaryOperator, op)) (2)

const BinaryOperation = factory.concept("BinaryOperation", ConceptModifier.concrete).implementing(Operation) (3)
factory.property(BinaryOperation, "operator").ofType(BinaryOperator)
factory.containment(BinaryOperation, "left").ofType(Value)
factory.containment(BinaryOperation, "right").ofType(Value)

factory.concept("BooleanType", ConceptModifier.concrete).implementing(Type) (4)
```

1. Construct an *enumeration* (as an instance of LionWeb’s `Enumeration` type) named `BinaryOperator`.
2. Construct *enumeration literals* (as instances of LionWeb’s `EnumerationLiteral` type) named `and` and `or`. We’ll later extend this list with other binary operators. Note that semicolons are generally unneeded in TypeScript code, thanks to Automatic Semicolon Insertion (ASI). However, in some situations the TypeScript parser needs a little help, such as when starting a statement with an array literal. In cases like that, it’s somewhat customary to add one semicolon at the beginning of the line (rather than at the end of the previous line).
3. Construct a `BinaryOperation` concept, with an `operator` property of type `BinaryOperator`, and `left` and `right` *containments* of type `Value`: these are the binary operation’s *operands*. A containment is a parent-child relation between the parent type – here: `BinaryOperation` – and the child type — here: `Value`.
4. Construct a `BooleanType` concept, which implements `Type` interface.

💡

****Design choice**  
  
I don’t want to create a **separate* concept for boolean binary operations — rather, I want **one* concept for **any* binary operation. This is because I like to keep the number of concepts relatively low, and not have a very deep hierarchy. If we made `BinaryOperation` an interface, we’d necessarily get an explosion of concrete subconcepts: essentially one for each possible result type of binary operations, so `BooleanBinaryOperation`, `IntegerBinaryOperation`, etc. That doesn’t seem very [DRY](https://en.wikipedia.org/wiki/Don%27t%5Frepeat%5Fyourself?ref=dsl-consultancy.ghost.io).

![](https://storage.ghost.io/c/eb/4d/eb4df6b9-0e4f-4d29-b975-4075848c0001/content/images/2026/09/boolean-base-entities.svg)

**The boolean base entities, including base interfaces for clarity*

Running the `generate` NPM task of the `build` package produces TypeScript classes for `BooleanType`, `BooleanLiteral`, and `BinaryOperation`, and a `BinaryOperator` enumeration. To instantiate these classes, we should use the `create` methods they all expose. These `create` methods take a unique identifier ([UUID](https://en.wikipedia.org/wiki/Universally%5Funique%5Fidentifier?ref=dsl-consultancy.ghost.io)) as their first argument. To randomly generate such (UU)IDs we use the `nanoid` library, but nicely encapsulated as follows, in a new file `packages/my-fpl/src/ids.ts`:

```
import { nanoid } from "nanoid" (1)

export const newId = () => nanoid() (2)
```

1. Import the `nanoid` library – which is actually a function – to generate unique IDs. This relies on having executed `npm add nanoid` before.
2. Define a `newId` function that simply calls the `nanoid` function, which generates a random ID that’s practically guaranteed to be unique.

This encapsulation might look a bit…trite, but along the course of this blog series it’ll turn out to be somewhat handy. Instead of needing to patch existing code, we’ll just work off our crystal ball and head these changes off at the pass.

Now, we can instantiate these classes as follows, to construct an AST:

```
import { newId } from "./ids.js" (1)
import { BinaryOperation, BinaryOperator, BooleanLiteral } from "./MyFPL.g.js" (2)

const value = BinaryOperation.create(newId()) (3)
value.operator = BinaryOperator.and
const leftExpr = BooleanLiteral.create(newId())
leftExpr.value = true
const rightExpr = BooleanLiteral.create(newId())
rightExpr.value = false
```

Constructing a boolean value as an AST (without convenience)

1. Import the `newId` function from the `packages/my-fpl/src/ids.ts` file.
2. Import the classes related to booleans and binary operations from the `packages/my-fpl/src/MyFPL.g.ts` file.
3. Instantiate an instance of the `BinaryOperation` class, by calling its static `create` method with a randomly-generated ID. The regular constructors of these generated classes should not be used.

💡

In LionWeb, any node can only appear ****once** in any AST. That means we can’t re-use existing nodes, and have to instantiate e.g. a `BooleanLiteral` every time a boolean literal is needed.  
  
This seems tedious, but is central to LionWeb’s functioning.

The code in the listing above constructs an AST that’s equivalent to the expression `true && false` in e.g. JavaScript. As such, it seems a bit cumbersome. If only we already had a proper syntax, and an editor for that. We’re going to concern ourselves with (editable) syntax in the next blog post. But even with a proper syntax, we’d like to construct ASTs in a “shorthand” way, e.g. for writing unit tests.

To that end, we’ll make a small class with “shorthand” convenience factory methods, in a file `shorthands.ts`:

```
import { newId } from "./ids.js"
import { BinaryOperation, BinaryOperator, BooleanLiteral, Value } from "./MyFPL.g.js"

export class Shorthands { (1)

    get booleanShorthands() { (2)
        const booleanLiteral = (value: boolean) => {
            const node = BooleanLiteral.create(newId())
            node.value = value
            return node
        }
        return {
            booleanLiteral: booleanLiteral,
            trueLiteral: () => booleanLiteral(true),
            falseLiteral: () => booleanLiteral(false)
        }
    }

    binaryOperation(operator: BinaryOperator, left: Value, right: Value) {
        const node = BinaryOperation.create(newId())
        node.operator = operator
        node.left = left
        node.right = right
        return node
    }

}
```

A class whose instances expose convenience factory methods: “shorthands”

1. Create a class, so we can pass additional arguments to its constructor later on, if needed.
2. Add a getter property `booleanShorthands` that returns an object that encapsulates all shorthands that are entirely specific to booleans: `booleanLiteral(<bool>)`, `trueLiteral`, and `falseLiteral`. Note that these shorthands – as is the `binaryOperation` shorthand – are functions.

With the code in the listing directly above, we can re-phrase the code in the earlier listing as follows:

```
import { BinaryOperator } from "../MyFPL.g.js"
import { Shorthands } from "../shorthands.js"

const {binaryOperation, booleanShorthands} = new Shorthands() (1)
const {trueLiteral, falseLiteral} = booleanShorthands (2)

export const expr = binaryOperation(BinaryOperator.and,
    /* left operand : */ trueLiteral(),
    /* right operand: */ falseLiteral()
)
```

Constructing a boolean value as an AST (with convenience)

1. Create an instance of the `Shorthands` class, and destructure it to obtain the `binaryOperation`, and `booleanLiteral` convenience factory methods (as functions).
2. Destructure the `{true|false}Literal` shorthands from the `booleanShorthands` object.

An MyFPL program can currently consist of only one `Value`, and the only instances of `Value` we can construct are `BooleanType` (which we’ll use only later), `BooleanLiteral`, and `BinaryOperation`.

💡

In this blog post, we’ve implemented the notion of **booleans*. In the next blog post, we’re going to implement an interpreter for `Value`s.

© 2026 Meinte Boersma (DSL Consultancy)

---

### Thanks

Thanks to Corno Schraverus for suggesting the “shorthands” name, and allowing me to steal it!