4.8 Variables in Structs

Fields are not the only entity that can appear in the definition of a struct type.

Suppose that after reading more carefully the Packet Specification 1.2 (that spans for several thousand of pages) we realize that the field size doesn’t really store the number of bytes of the payload and control arrays, like we thought initially. Or not exactly: the Packet Foundation says that if size has the special value 0xff, then the size is zero.

We could of course do something like this:

type Packet =
  struct
  {
    byte magic = 0xab;
    byte size;

    byte[size == 0xff ? 0 : size] payload;
    byte[size == 0xff ? 0 : size] control;
  };

However, we can avoid replicating code by using a variable instead:

type Packet =
  struct
  {
    byte magic = 0xab;
    byte size;

    var real_size = (size == 0xff ? 0 : size);

    byte[real_size] payload;
    byte[real_size] control;
  };

Note how the variable can be used after it gets defined. In the underlying process of mapping or constructing the struct, the variable is incorporated into the lexical environment. Once defined, it can be used in constraint expressions, array sizes, and the like. We will see more about this later.

Incidentally, it is of course possible to use global variables as well. For example:

var packet_special = 0xff;
type Packet =
  struct
  {
    byte magic = 0xab;
    byte size;

    var real_size = (size == packet_special ? 0 : size);

    byte[real_size] payload;
    byte[real_size] control;
  };

In this case, the global packet_special gets captured in the lexical environment of the struct type (in reality in the lexical environment of the implicitly created mapper and constructor functions) in a way that if you later modify packet_special the new value will be used when mapping/constructing new values of type Packet. Which is really cool, but let’s not get distracted from the main topic... :)