Hi everyone, ok so I’m playing around with a shell implementation of mine, and I’m trying to translate it in zig, so far so good, in this project I have to use readline to read the inputs, the problem is the prototype of the readline function doesn’t express the fact that it can return null ? so I’ve tried to express the nullability myself, but evidently failed to do so, and I was hopping I missed something, otherwise the rest is working as expected, I can type and use readline from zig no problem
And that gets called from span… which gets called from your readline.
Have you tried inspecting that pointer first? As in actually checking the numeric value of it before handing it to span? Essentially, std.mem.len is documented to assume non-null. I’m curious what you’ll get if you print the address from that pointer in the problematic case.
so how should I implement this ? because it seems weird to have to cast the pointer to check if it’s zero, but maybe that’s the only solution, I just thought that maybe there was a way to coerce the fact that zero is indeed null ?
By that logic, [*c] can legitimately carry the value 0. You’ll have to inspect that value first then because it doesn’t get expressed as null. Makes sense though - they have to be compatible with C-pointers and… well… that’s a thing so…
Yes I think I’m just going to wrap it in the little check function that I’ve made, and call it a day, thanks for your help, tho. I’m still curious as to why it doesn’t just assume null ability from C pointers translations right of the bat, like for me every C pointer should be considered a nullable pointer by default, because well it’s C so you never know, but maybe there’s a good reason why that’s not the case.
This is the problem, ?[*c]u8 doesn’t act like a proper optional where 0 is equivalent to null, I don’t completely understand the details, but it seems that ?[*c]u8 is basically like [*c]u8 just that it tricks zig into allowing optional syntax.
I think in practical terms you just have to try to avoid using [*c] within zig as much as possible. One way to do this here, is to define the signature for the readline function manually:
I don’t know why ?[*c]u8 acts like an optional with broken invariants, maybe it is needed for some kind of tricky c compatibility edge case. But would be good to know, if there is a reason for it behaving that way.
Obviously, we can see that this will infact return true because p2 is just a copy of p1 and p1 has the zero-address. That works fine.
This however is what was happening in @pierrelgol’s case:
const p1: [*c]u8 = @ptrFromInt(0);
const p2: ?[*c]u8 = p1; // is optional now
return p2 == null;
Now, p2 is optional. The optional has a value of p1, so the optional itself is not null. The pointer that it’s holding onto IS null though so it sneaks by this check. This is a great footgun example. I’m going to mark this as the solution because this is actually what is happening here.
So @pierrelgol, what you really need to do here is just treat the [*c] like you would any other optional pointer. It does in fact work with orelse. You don’t need to hand it to another pointer with a qualified optional - you can go directly against the pointer itself.
Ok, thanks everyone for the details, but now that you uncovered that situation, I’d really like an answer lol, is this a bug or is this intended ? because if it is intended I think that this is a serious footgun indeed, and I’d really want to hear why that’s the case.
EDIT: I mean to be fair it does make sense, because I also expect every C pointers to be considered possibly null, but the syntax is weird
I believe this is infact intended behaviour but it’s really sneaky.
An optional pointer may not have been assigned to a pointer yet, but that says nothing about the address of the pointer that it’s holding onto. It technically makes perfect sense, but we’re so used to ? being associated with null that it doesn’t come to mind when using [*c] pointers which also have their own semantics surrounding null and orelse.