Types
The powerful type system is one of the features that make Spade stand out the most compared to contemporary HDLs. For software developers already familiar with Rust, the Spade type system is very similar to that of Rust, to the point where you can skim this section and assume that you’re writing Rust.
Structs
Like most languages, Spade supports structs to encapsulate related values. For example, a struct containing a field named a with type int<8> and b with type bool can be written as:
struct IntAndBool {
a: int<8>,
b: bool
}
Structs are initialized as if they are functions. This means you can either do so with positional arguments:
let instance = IntAndBool(0, true);
or with named arguments:
let instance = IntAndBool$(a: 0, b: true);
Like many languages, accessing struct fields is done with . like:
let x = instance.a;
let y = instance.b;
Tuples
Sometimes, defining a named struct just to group values is overkill, which makes tuples
a useful alternative. Tuple types are written as (type1, type2, ...) and values are written
as (a, b, ...). As an example, a function that wraps an int<8> and a bool into a tuple can
be written as:
fn example(a: int<8>, b: bool) -> (int<8>, bool) {
// ^^^^^^^^^^^^^^ Return a tuple
(a, b)
// ^^^^^^ Construct the return value
}
Tuple elements can be accessed using the . operator:
let a = tup.0;
let b = tup.1;
though in most cases it is better to use destructuring.
Destructuring
Tuples, structs, and most other types can be destructured to gain access to the inner values. For example, the tuple indexing above can be replaced with:
let (a, b) = tup;
The big advantage of destructuring over indexing is that you cannot forget to
account for all fields. If someone adds another field to tup, you will get a
compilation error saying that field also needs to be taken into account.
Structs can also be destructured, and like instantiation it can be done with both positional and named arguments:
let IntAndBool(x, y) = instance;
let IntAndBool$(a: x, b: y) = instance;
Like named arguments, you can also use shorthand notation, to bind a field name to a variable of the same name:
let IntAndBool$(a, b) = instance;
// Is the same as
let a = instance.a;
let b = instance.b;
Destructuring can also be done recursively, for example:
let (IntAndBool(x, y), z) = instance_and_bool;
Arrays
Arrays too work like most other languages. They are a collection of a fixed
number of identically typed values. Array types are written as [T; N] where T is
the contained type and N is the number of elements. For example, an array
of ten 8-bit integers is written as [int<8>; 10]. For more details on initializing
and accessing arrays, see the previous Basic Expressions chapter.
More fancy Types
Beyond these types which are similar to those found in many languages, Spade has some more powerful type system features that are discussed in the next section.