#optional pointer assignment

1 messages · Page 1 of 1 (latest)

lean rose
#

I'm not sure why I can't find the answer to this anywhere, so I'll ask it here: how can I allocate and assign to an optional pointer? Very new to zig. Thanks!

const std = @import("std");
const print = std.debug.print;
const test_allocator = std.testing.allocator;

test "optional pointer" {
    const Stru = struct {
        id: usize,
    };
    var o: ?*Stru = undefined; // doesn't work, nor does *?Stru
    o = try test_allocator.create(Stru);
    o.* = .{ .id = 2 };
    print("o: {}", .{o});
}
sand compass
#

when you say the var assignment doesn't work, what do you mean

#

I think it's probably failing at o.* because you're trying to dereference an optional

#

you probably mean o.?.*

#

also there's kind of no point making o undefined, just make it null

lean rose
#

Ah! Couple helpful things in your comment. Thank you!

sand compass
#

no problem

lean rose
#

What's the appropriate way to destroy an optional pointer? test_allocator.destroy(o) fails with

error: access of union field 'Pointer' while field 'Optional' is active
    const info = @typeInfo(@TypeOf(ptr)).Pointer;
                 ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
~/Dev/Libs/zig/lib/std/builtin.zig:228:18: note: union declared here
pub const Type = union(enum) {
                 ^~~~~
#

Ah, it would be, I guess, .destroy(o.?)... which wouldn't have been what I thought since the dereferecing points to the created instance and not the allocated memory slot. But OK! Thanks again

sand compass
#

just note that optional pointers aren't generally used that much in zig, unless you need to call C code

opal sedge
lean rose
#

Ok... I think I misunderstood what these two lines mean, then:

o = try test_allocator.create(Stru);  // Line#1
o.* = .{ .id = 2 };  // Line#2

I had (incorrectly I guess) thought that Line#1 assigns the allocated address to the variable o, while Line#2 initializes whatever is at that memory address, so it would be the allocated memory address we'd want to destroy, and not the thing that is there. Perhaps the dereference is the handle to the memory, and not the o value?

sand compass
#

pointers don't need to be optional

#

so imagine you had

var o: *Stru = undefined;

rather than a ?*Stru it'll be easier to reason about. Basically, o is a pointer and when you dereference it with o.* = .{.id=2} you're saying "give me the actual memory that this o points to, and set that memory to Stru{.id=2}

lean rose
#

I think I see your point there, @sand compass, because you'd destroy it with .destroy(o) and not .destroy(o.*).

#

Thanks to you both on this - I learned a lot more about this than my original question!

lean rose
# sand compass just note that optional pointers aren't generally used that much in zig, unless ...

Is there a better way to handle my use-case? I am working through "Let's write a database" which is in C. In it there are tables with pages filled with rows. The structs are below. Pages are created as-needed, as are Rows. In my case I check if the appropriate page is loaded already and, if not, allocate and stick in table.pages at the appropriate index. I was using Nullable (optional) pointers to handle whether I needed to allocate a new page||row, rather than keep page_counts and row_counts around as a secondary source.

const PAGE_SIZE = 4096; // 4KB = 4096 (Bytes, dec.)
const TABLE_MAX_PAGES = 200;
const ROWS_PER_PAGE = 14;
const TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;

const Table = struct {
    num_rows: usize = 0,
    num_pages: usize = 0,
    pages: [TABLE_MAX_PAGES]*Page = undefined,
};

const Page = struct {
    num_rows: u32 = 0,
    rows: [ROWS_PER_PAGE]*Row = undefined,
};

const Row = struct {
    id: []const u8 = undefined,
    usernm: []const u8 = undefined,
    email: []const u8 = undefined,

    const COL_USERNM_LEN = 32; // bytes
    const COL_EMAIL_LEN = 255; // bytes
    const COL_ID_LEN = 4; // bytes (u32 bits)
};
#

Is o = try test_allocator.create(Stru); syntactic sugar for o.? = try test_allocator.create(Stru);?

#

I understand what's happening, in a general sense. I went to write it again later tonight and forgot whether to include the o.? in the original assignment, so for future remembering i'm just wondering if it's syntactic sugar or idiom or maybe "it's how zig works"...

split umbra
#

o.? = is not valid syntax, o = ...; means replace the entire value with either null or a value of the optional child type. o.? means assert the optional isn't null and get the underlying value.