Structs

A struct is Falx's only user-defined compound type: a name, a list of fields (each with an optional default), and a set of methods.

struct Player {
    health = 100;
    name;

    func takeDamage = define(amount) {
        health -= amount; // fields are read/written directly, no `this.`/`self.`
    }

    func isAlive = define() {
        return health > 0;
    }
}

let p = Player();
p.name = "Hero";
p.takeDamage(30);
output(p.health);    // 70
output(p.isAlive());  // true
output(typeof(p));    // "Player" -typeof() on an instance is the struct's own name

Fields & defaults

Declare a field with just a name (name;) or with a default value (health = 100;). Field declarations and method declarations can be interleaved in any order inside the struct body.

Constructing an instance

Calling the struct's name like a function creates an instance. Arguments are matched to fields positionally, in declaration order -there's no named-argument syntax and no way to skip a middle field while setting a later one.

The constructor is more lenient about argument count than a normal function call. You can pass anywhere from zero arguments up to the total number of fields -any field you don't supply a value for falls back to its own default, or to null if it has none. A runtime error is only raised if you pass more arguments than the struct has fields; passing too few, even for fields with no default, is accepted silently.
struct Point {
    x;
    y;
    label = "origin";
}

Point();                       // x=null, y=null, label="origin" -no error
Point(1, 2);                    // x=1, y=2, label="origin"
Point(1, 2, "custom");         // x=1, y=2, label="custom"
Point(1, 2, "custom", "extra"); // runtime error: Expected 3 arguments, but got 4

Given this, it's worth treating "required" fields as a convention you enforce yourself (e.g. an assert() at the top of a method, or simply always passing every field) rather than something the language checks for you. That "too many arguments" case is E1021 in the errors reference; accessing or setting a field that was never declared is E1012/E1014.

Methods

A method is declared with func <name> = define(...) { ... } inside the struct body, exactly like a top-level function. Inside a method, every field of the struct is available directly by name -reading it reads the instance's value, and assigning to it (field = ... or field -= ...) mutates the instance. There is no this/self keyword.

Accessing fields and methods from outside

Use dot access, both to read and to assign:

let p = Player();
p.name = "Hero";   // set a field from outside
output(p.health);  // read a field
p.takeDamage(10); // call a method

Accessing a field or method name that doesn't exist on the struct raises a runtime error rather than returning null.

Equality

Two struct instances are == if they're instances of the same struct definition and every field currently holds an equal value -value equality of the whole instance, not reference identity.

Structs across files

Structs are ordinary top-level declarations, so a struct defined in one .flx file is exported like anything else when another file requires it. See Modules and the structs-across-modules tutorial.