Structs

A struct is a user defined grouping of several data fields together. Unlike an array, a struct can store non-similar data types together in contiguous memory.

Declaring a struct

Here is how you declare a struct:

Student :: struct {
  name: string = "Calvin";
  id: int = 130958;
  grade: int = 100;
  age: int = 16;
  favorite_teacher: string = "Knox";
}

Initializing a member field in a struct, just like in C and C++, causes the initial value of the struct member to be initialized to that value. If no default value is provided to the member field, it will be initialized to zero.

Accessing Member Fields

A member field of a struct can be accessed using the dot . operator.

s: Student;
s.name = "Calvin";
s.id   = 0x10_31_15_17;
s.grade = 15;
s.age = 40;

print("The student's name is: %\n", s.name);

Anonymous Structs

Structs can be declared anonymously, without an identifier to identify what struct it is. This feature is useful in the case of creating complex data structures mixing anonymous unions and structs together.

// This is an anonymous struct.
variable := struct {
  x: int;
  y: int;
  z: int;
}

// complex Vector3 example using anonymous structs and unions
Vector3 :: struct {
  union {
    struct { x, y, z: float; }
    struct { r, g, b: float; }
    struct { s, t   : float; }
  }
}

Using on Structs

Jai allows using keyword on structs, importing the members into that particular scope.

We use struct inclusion on a to access x, y, and z directly without needing to do something such as a.x. Same example works with unions too.

Vec3 :: struct {
  x: float; y: float; z: float;
}

a: Vec3 = Vec3.{1,2,3};
using a;
print("a.x=%\n", x); // no need to do a.x, just access x directly

using can used on structs to do a C++ inheritance-like feature. By putting using a: A; on the B struct, B can implicitly cast to A as follows:

A :: struct {
  data: int;
}

B :: struct {
  using a: A;
}

function :: (a: A) {
  print("Calling f :: (a: A)\n");
}

b: B;
function(b); // here, B implicitly casts to A

using can be applied to a function parameter.

funct1 :: (using a: A) {
  // note that using a allows us to access 'data' directly without doing a.data
  print("a.data=%\n", data);
}

Gotchas

Unlike C++, Java, or any other object-oriented language, structs do not have public or private data. All data fields in a struct are public, with no way to change the fields to private. Any function can modify and change struct member fields.

Unlike C++, Java, or any other object-oriented language, structs do not have member functions associated with them. There is no concept of functions “belonging” to a particular object. Functions can be declared inside structs, but functions inside structs are only using the struct as a namespace.

For example:

Obj :: struct {
  x: int;
  set_x :: (obj* Obj, x: int) {
    obj.x = x;
  }
}

o: Obj;
// o.set_x(100); // this is not allowed
obj.set_x(*o, 100);