Basics

fble-0.5 (2025-07-13,fble-0.4-212-ga8f8ad0f)

This tutorial walks you through the basics of fble: structs, unions, and functions. You'll implement a bitwise AND operation on a 4 bit bit-vector.

In your favorite text editor, start a new file called Basics.fble.

Module Imports

We'll start by reusing some imports from the HelloWorld tutorial:

# Imports
@ String@ = /Core/String%.String@;
% Str = /Core/String%.Str;
% Strs = /Core/String%.Strs;

Types

Next we define types for a single bit and a 4 bit bit-vector:

@ Unit@ = *();
@ Bit@ = +(Unit@ 0, Unit@ 1);
@ Bit4@ = *(Bit@ 3, Bit@ 2, Bit@ 1, Bit@ 0);

This code defines three types, named Unit@, Bit@, and Bit4@. The language requires type names to end with the @ character, to distinguish them from normal variable names.

The @ at the beginning of each line says we are defining names of types. The syntax *(...) is used for struct types and +(...) for union types.

The Unit@ type defined here is a struct type without any fields. We call it Unit@ because there's only one possible value for the type. It is a building block for the Bit@ type. Unit@ is equivalent to the () type in Haskell, or the type of a zero-element tuple () in Python.

The Bit@ type is defined as a union of two Unit@ types, labeled 0 and 1. There are two possible values for the Bit@ type, a Unit@ value tagged with 0 and a Unit@ value tagged with 1. Union values implicitly keep track of their tag, unlike in C. You can ask a union value what its tag is and access the value associated with the tag. More on that later. There is nothing special about the names of the fields 0 and 1 that we have chosen here. We could just as well have named them zero and one. The fble language has no notion of built in numbers, which means you are free to use numbers as identifiers for variable names or field names.

Bit4@ is a struct type with four fields, named 3, 2, 1, and 0. Each field has type Bit@. This represents a bit vector of 4 bits. We'll call bit 3 the most significant bit and put it on the left as is conventional, but it doesn't really matter for the bitwise operations defined in this tutorial.

Values

Now that we have the Bit@ and Bit4@ types defined, we can declare some variables of those types:

Unit@ Unit = Unit@();

Bit@ 0 = Bit@(0: Unit);
Bit@ 1 = Bit@(1: Unit);

Bit4@ X = Bit4@(0, 0, 1, 1);
Bit4@ Y = Bit4@(1, 0, 1, 0);

This code declares 5 variables, named Unit, 0, 1, X, and Y. The variable declarations start with the type of the variable, followed by the name of the variable, =, and the value of the variable.

The syntax to create a struct value is the struct type followed by the list of values for each field of the struct, in order, in parenthesis. The syntax to create a union value is the union type followed by the tag, a colon, and the value to use for that tagged field all in parenthesis.

Union and struct values are immutable, lightweight, and passed by value. A decent implementation of fble will implement a value of Bit4@ like X or Y easily in a single machine word.

Functions

Next we'll define a couple of functions that implement a bitwise AND operation: A function And that computes the AND operation on individual bits, and a function And4 to compute bitwise AND on our 4 bit bit-vectors:

(Bit@, Bit@) { Bit@; } And = (Bit@ a, Bit@ b) {
  a.?(0: 0, 1: b);
};

(Bit4@, Bit4@) { Bit4@; } And4 = (Bit4@ a, Bit4@ b) {
  Bit4@(And(a.3, b.3), And(a.2, b.2), And(a.1, b.1), And(a.0, b.0));
};

The functions And and And4 are variables just like Unit, 0, 1, X, and Y. To declare these variables, we start with the type, followed by the name, =, and the their value. In this case we have function types and function values instead of struct or union types and struct or union values.

The syntax for a function type is the list of argument types in parenthesis, followed by the return type of the function in braces. The type for the And function is (Bit@, Bit@) { Bit@; }, which means it is a function that takes two arguments of type Bit@ and returns a Bit@ as a result.

The syntax for a function value is a list of named arguments in parenthesis followed by the body of the function. The implementation of the And function uses names a and b for the arguments. The body of the function consists of a single expression, which will be evaluated to compute the result of the function.

In the case of the And function, the result is computed using the conditional expression a.?(0: 0, 1: b). Conditional expressions, also known in fble as "union select" expressions, are similar to the conditional operator, if statements, or case statements in C and other languages. The syntax for a conditional expression is the union value to switch on, followed by .?, followed by an expression to evaluate for each possible tag of the union value. At runtime, the tag associated with the union value is used to select the expression to return. In this case, if a is tagged with 0, the result 0 will be returned, and if a is tagged with 1, the result b will be returned. That defines an AND operation.

The And4 function is similarly defined. It returns a Bit4@ value whose fields are the result of applying the And function to the corresponding fields of the arguments a and b. For example, And(a.3, b.3) calls the And function with bit 3 of a and bit 3 of b, and uses the result for bit 3 of the result of the And4 function.

We can apply our And4 function to variables X and Y to get a result Z:

Bit4@ Z = And4(X, Y);

String Conversions

We'd like to write some functions to convert Bit@ and Bit4@ values to strings so we can print them out. These functions are similar to the functions we have already written:

(Bit@) { String@; } ShowBit = (Bit@ a) {
  a.?(0: Str|0, 1: Str|1);
};

(Bit4@) { String@; } ShowBit4 = (Bit4@ a) {
  Strs[ShowBit(a.3), ShowBit(a.2), ShowBit(a.1), ShowBit(a.0)];
};

We'll explain in more detail about the list and string literals used here in future tutorials.

The Output String

All that's left is to set our output string and main function. We'll have the program print out the values of X, Y, and Z:

String@ output = Strs[
  ShowBit4(X), Str|' AND ', ShowBit4(Y), Str|' = ', ShowBit4(Z)];

/Core/Stdio/StringO%.Run(output);

Running the program

We can now run our program to try it out:

fble-stdio -p core -I . -m /Basics%

If all goes well, you should see the values of X, Y, and Z printed out:

0011 AND 1010 = 0010

Exercises

Try implementing bitwise NOT, OR and XOR functions.

Try defining a Bit8@ type and implementing a bitwise And8 operation for it. You could reuse Bit4@ for the definition of Bit8@ or just use Bit@ like how we defined Bit4@.

Try implementing a 4-bit Add function that can add two Bit4@ interpreted as twos-complement integers.

Next Steps

Head over to the Variables tutorial to learn all about variables.