Skip to content

Special methods

Chung Leong edited this page Jul 22, 2024 · 2 revisions

Each Zig object has a number of special methods:

Multi-item pointers have the following methods:

valueOf()

This method creates a "JavaScript version" of a Zig data object. Structs become regular JavaScript objects. Arrays and vectors become regular JavaScript arrays. Enums become strings. Pointers become the valueOf() of their targets.

This function is able to handle recursive references. Example:

const std = @import("std");

const NodeType = enum { red, blue };
pub const Node = struct {
    type: NodeType,
    id: i64,
    parent: ?*const @This() = null,
    children: ?[]*const @This() = null,
};

pub fn getRoot(allocator: std.mem.Allocator) !*const Node {
    const root: *Node = try allocator.create(Node);
    root.* = .{ .type = .red, .id = 0 };
    const child1: *Node = try allocator.create(Node);
    child1.* = .{ .type = .blue, .id = 1, .parent = root };
    const child2: *Node = try allocator.create(Node);
    child2.* = .{ .type = .blue, .id = 2, .parent = root };
    const children = try allocator.alloc(*Node, 2);
    children[0] = child1;
    children[1] = child2;
    root.children = children;
    return root;
}
import { getRoot } from './valueof-example-1.zig';

const root = getRoot();
console.log(root.valueOf());
<ref *1> {
  type: 'red',
  id: 0n,
  parent: null,
  children: [
    { type: 'blue', id: 1n, parent: [Circular *1], children: null },
    { type: 'blue', id: 2n, parent: [Circular *1], children: null }
  ]
}

This method is useful when you need to dump an object into the development console.

toJSON()

This method is called when JSON.stringify() is used on an object. It behaves mostly like valueOf() except for treatment of error objects and big integers. While valueOf() returns these as-is, toJSON() tries to make them fit the JSON format. Errors are converted to { error: "[MESSAGE]" }. Big integers, provided that they're between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER, are converted to regular numbers:

const JediError = error{ fell_to_the_dark_side, lightsaber_low_battery };
const JediStruct = struct {
    age: u64 = 72,
    err: JediError = JediError.fell_to_the_dark_side,
};
pub const jedi: JediStruct = .{};
import { jedi } from './tojson-example-1.zig';

console.log(jedi.valueOf());
console.log(jedi.toJSON());
{ age: 72n, err: [ZigError: Fell to the dark side] { number: 47 } }
{ age: 72, err: { error: 'Fell to the dark side' } }

delete()

This method frees any fixed memory allocated for a Zig data object. Allocation of fixed memory happens when an object is created using the fixed: true option of the constructor or when it comes into being through auto-vivification during assignment to a fixed memory pointer.

No deallocation would happen if the object isn't in fact backed by fixed memory. Reference to its memory buffer is simply removed. Example:

pub const User = struct {
    first_name: []const u8,
    last_name: []const u8,
};

pub var current_user: ?User = null;
import module, { User } from './delete-example-1.zig';

// object in JavaScript memory
const user = new User({ first_name: 'Abraham', last_name: 'Lincoln' });
user.delete();
try {
  console.log(user.valueOf());
} catch (err) {
  console.log(err.message);
}

// object in Zig memory
module.current_user = { first_name: 'Abraham', last_name: 'Lincoln' };
module.current_user.first_name.delete();
module.current_user.last_name.delete();
module.current_user.delete();
try {
  console.log(module.current_user.valueOf());
} catch (err) {
  console.log(err.message);
}
Cannot read properties of null (reading 'byteOffset')
Cannot read properties of null (reading 'byteOffset')

slice(start, end)

This method creates a copy of a particular portion of the pointer's target, indicated by start and end (not inclusive). Negative indices are counted from the end of the parent slice. Example:

pub const PtrI32 = []i32;
import { PtrI32 } from './slice-example-1.zig';

const sliceO = new PtrI32([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
const sliceA = sliceO.slice(1, 5);
console.log('SliceA before:', [ ...sliceA ]);
sliceA[0] = 100;
console.log('SliceA after:', [ ...sliceA ]);
console.log('SliceO after:', [ ...sliceO ]);

const sliceB = sliceO.slice(-9, -1);
console.log('SliceB:', [ ...sliceB ]);

const sliceC = sliceO.slice();
console.log('SliceC:', [ ...sliceC ]);
sliceA before: [ 1, 2, 3, 4 ]
sliceA after: [ 100, 2, 3, 4 ]
sliceO after: [
  0, 1, 2, 3, 4,
  5, 6, 7, 8, 9
]
sliceB: [
  1, 2, 3, 4,
  5, 6, 7, 8
]
sliceC: [
  0, 1, 2, 3, 4,
  5, 6, 7, 8, 9
]

subarray(start, end)

This method returns a portion of the pointer's target, indicated by startand end (not inclusive). Negative indices are counted from the end of the parent slice. Example:

pub const PtrI32 = []i32;
import { PtrI32 } from './subarray-example-1.zig';

const sliceO = new PtrI32([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
const sliceA = sliceO.subarray(1, 5);
console.log('sliceA before:', [ ...sliceA ]);
sliceA[0] = 100;
console.log('sliceA after:', [ ...sliceA ]);
console.log('sliceO after:', [ ...sliceO ]);

const sliceB = sliceO.subarray(-9, -1);
console.log('sliceB:', [ ...sliceB ]);

const sliceC = sliceO.subarray();
console.log('sliceC:', [ ...sliceC ]);
sliceA before: [ 1, 2, 3, 4 ]
sliceA after: [ 100, 2, 3, 4 ]
sliceO after: [
  0, 100, 2, 3, 4,
  5,   6, 7, 8, 9
]
sliceB: [
  100, 2, 3, 4,
    5, 6, 7, 8
]
sliceC: [
  0, 100, 2, 3, 4,
  5,   6, 7, 8, 9
]```

---
[Special properites](Special-properties)
Clone this wiki locally