-
Notifications
You must be signed in to change notification settings - Fork 3
Pointer
A pointer is a variable that points to other variables. It holds a memory address. It also holds a length if it's a slice pointer.
Zigar auto-deferences a pointer when you perform a property lookup:
const std = @import("std");
pub const StructA = struct {
number1: i32,
number2: i32,
pub fn print(self: StructA) void {
std.debug.print("{any}\n", .{self});
}
};
pub const StructB = struct {
child: StructA,
pointer: *StructA,
};
pub var a: StructA = .{ .number1 = 1, .number2 = 2 };
pub var b: StructB = .{
.child = .{ .number1 = -1, .number2 = -2 },
.pointer = &a,
};
import module from './pointer-example-1.zig';
console.log(module.b.child.number1, module.b.child.number2);
console.log(module.b.pointer.number1, module.b.pointer.number2);
In the example above, child
is a struct in StructB
itself while pointer
points to a struct
sitting outside. The manner of access is the same for both.
Assignment works the same way:
import module from './pointer-example-1.zig';
module.b.child.number1 = -123;
module.b.pointer.number1 = 123;
module.b.child.print();
module.b.pointer.print();
module.a.print();
pointer-example-1.StructA{ .number1 = -123, .number2 = -456 }
pointer-example-1.StructA{ .number1 = 123, .number2 = 456 }
pointer-example-1.StructA{ .number1 = 1, .number2 = 2 }
Notice how a
has been modified through the pointer.
Assignment to a pointer changes its target:
import module from './pointer-example-1.zig';
module.b.child = { number1: -123, number2: -456 };
module.b.pointer = { number1: 123, number2: 456 };
module.b.child.print();
module.b.pointer.print();
module.a.print();
pointer-example-1.StructA{ .number1 = -123, .number2 = -456 }
pointer-example-1.StructA{ .number1 = 123, .number2 = 456 }
pointer-example-1.StructA{ .number1 = 1, .number2 = 2 }
While the assignment to child
altered the struct, the assignment to pointer
actually changed
the pointer's target to a new instance of StructA
, created automatically by Zigar when it detected that
the object given isn't an instance of StructA
. It's equivalentt to doing the following:
module.b.pointer = new StructA({ number1: 123, number2: 456 });
In order to modify the target of a pointer as a whole, you'd need to explicitly deference the pointer:
import module from './pointer-example-1.zig';
module.b.pointer['*'] = { number1: 123, number2: 456 };
module.a.print();
The above code is equivalent to the following Zig code:
b.pointer.* = .{ .number1 = 123, .number2 = 456 };
a.print();
In both cases we're accessing '*`. JavaScript doesn't allow asterisk as a name so we need to use the bracket operator.
Explicity dereferencing is also required when the pointer target is a primitive like integers:
pub var int: i32 = 123;
pub var int_ptr = ∫
import module from './pointer-example-2.zig';
console.log(module.int_ptr['*']);
module.int_ptr['*'] = 555;
console.log(module.int);
module.int_ptr = 42;
console.log(module.int);
123
555
555
You can see once again here how assignment to a pointer changes its target (int
was not set to
42).
Certain operations that use
Symbol.toPrimitive
would trigger auto-defererencing of primitive pointers:
import module from './pointer-example-2.zig';
console.log(`${module.int_ptr}`);
console.log(Number(module.int_ptr));
console.log(module.int_ptr == 123);
123
123
true
const std = @import("std");
pub const File = struct {
name: []const u8,
data: []const u8,
};
pub const Directory = struct {
name: []const u8,
entries: []const DirectoryEntry,
};
pub const DirectoryEntry = union(enum) {
file: *const File,
dir: *const Directory,
};
fn indent(depth: u32) void {
for (0..depth) |_| {
std.debug.print(" ", .{});
}
}
fn printFile(file: *const File, depth: u32) void {
indent(depth);
std.debug.print("{s} ({d})\n", .{ file.name, file.data.len });
}
fn printDirectory(dir: *const Directory, depth: u32) void {
indent(depth);
std.debug.print("{s}/\n", .{dir.name});
for (dir.entries) |entry| {
switch (entry) {
.file => |f| printFile(f, depth + 1),
.dir => |d| printDirectory(d, depth + 1),
}
}
}
pub fn printDirectoryTree(dir: *const Directory) void {
printDirectory(dir, 0);
}
import { printDirectoryTree } from './pointer-example-3.zig';
printDirectoryTree({
name: 'root',
entries: [
{ file: { name: 'README', data: 'Hello world' } },
{
dir: {
name: 'images',
entries: [
{ file: { name: 'cat.jpg', data: new ArrayBuffer(8000) } },
{ file: { name: 'lobster.jpg', data: new ArrayBuffer(16000) } },
]
}
},
{
dir: {
name: 'src',
entries: [
{ file: { name: 'index.js', data: 'while (true) alert("You suck!")' } },
{ dir: { name: 'empty', entries: [] } },
]
}
}
]
});
root/
README (11)
images/
cat.jpg (8000)
lobster.jpg (16000)
src/
index.js (31)
empty/