Fields

Field data.

Fields are the most obvious way to define and store data in a Stof document. Coming from other data formats like JSON or YAML, fields will feel very intuitive and familiar.

Navigation with paths can follow field names, also, so programmatically, it feels quite intuitive to work with.

Object: {
    strings: "my string data"
    numbers: 10ft + 3.55m
    
    Sub: {
        booleans: false
        lists: [
            {
                field: 42
                
                fn value() -> int {
                    self.field + 10
                }
            },
            +1_000,
            "Json arrays are Stof lists",
        ]
    }
}

#[main]
fn main() {
    const list_field = self.Object.Sub.lists;
    const value = list_field.front().value();
    assert_eq(value, 52);
}

Types

Fields that are defined with a type will keep that type, casting values to that given type when assigned. Otherwise, fields can have any value given to them!

str field: "temp"

#[main]
fn main() {
    self.field = 42;
    assert_eq(typeof self.field, "str");
    assert_eq(self.field, "42");
}

Const

Fields can also be defined as constant, throwing an error if an assignment occurs.

const str field: "perm"

#[main]
fn main() {
    let caught; // null initialization
    
    try self.field = 42;
    catch caught = true;
    
    assert(caught);
}

Private

Fields can also be private to the object that defines them.

Inner: {
    #[private]
    private_field: 'secret'

    #[test]
    fn can_see() {
        assert_eq(self.private_field, 'secret');
    }

    InnerInner: {
        #[test]
        fn cannot_see() {
            assert_not(super.private_field);
        }
    }
}

#[test]
fn cannot_see() {
    assert_not(self.Inner.private_field);
}

Creating Fields

While working with data, it is often needed to create new fields. This is accomplished with an assignment when assigning to a path. The field does not have to already exist, and any objects referenced in the path will be created (if not already existing) to make the path valid (including roots).

#[main]
fn main() {
    // creating a new field called "created" on "self"
    self.created = Time.now();
    assert(Time.now() >= self.created);
    
    // creating a new object "NewObject" on "root" and a new field called "nested"
    root.NewObject.nested = true;
}

Last updated

Was this helpful?