Zig 0.16 question(s)

I am in the process of porting from 0.15.2 to 0.16.0 which is much more tricky than I thought.
I run into several impossibilities. The first one…

Can’t we unwrap a variable anymore?

error: unable to unwrap null

If by unwrap you mean .? on null, you could never do that (without checked UB).
I personaly didnt run into any issues with my upgrades.
Can you provide more context?

Robert :blush:

Don’t forget to read the release notes. They are specifically intended to help make upgrading easier.

1 Like

I know for sure parentnode is not null here. Will not compile.

if (prevnode != null) {  
    if (parentnode.?.value) .... // error here
}

This does compile but needs an extra check :frowning:

if (prevnode != null and parentnode != null) {  
    if (parentnode.?.value) ....
}

What’s the type of parentnode? The error looks like it’s @TypeOf(null) (which is the type of a bare null literal and distinct from assigning null to an optional type)

example:

const val0 = null;
const val1: ?u32 = null;
comptime {
    assert(@TypeOf(val0) == @TypeOf(null));
    assert(@TypeOf(val1) != @TypeOf(null));
}
const assert = @import("std").debug.assert;

This has already been the case before 0.16.0 though.

No problems in 0.15.2…
The type is a nullable const pointer to a struct.

const parentnode: ?*const Node = if (!is_root) &self.nodes[ply - 1] else null;

Edit: should I create some “typed null”?

Wait forget what I said earlier I think the error would look different for that (something about ‘cannot unwrap @TypeOf(null)’), what you’ve got just looks like you’re unwrapping a null pointer at comptime which obviously doesn’t happen if you don’t take the branch that performs the unwrap via checking whether the value is null beforehand
Still not sure how 0.16.0 could have changed anything here, I think more context would help with answering this question. So far it looks like a logic bug to me?

1 Like

Yeah it is a quite complicated comptime thingy.

This is 0.15.2 down here:

here
it happens…

and in line 649 the “cannot unwrap” happens in 0.16

Another one: has the format duration {D} disappeared?

Not commenting on what the compiler should do here, but for what it’s worth:

  • is_root is comptime known when setting parentnode
  • parentnode can therefore be comptime known to be null when is_root is true
  • Line 649 which is triggering the error is effectively marked as reachable when is_root is true which doesn’t make sense

So, regardless of whether or not the compiler should error here, this is something that is worth your attention, as some part of this code can be marked as unreachable in some way, and doing so will eliminate some codegen of provably dead code (the line in question at least cannot be executed correctly when is_root is true, so i.e. guarding that line with if (!is_root) will stop that line’s code from being generated which seems good; I haven’t looked at the code hard enough to determine if more dead code could be eliminated than just that one line).

Yes, looks like that change was accidentally left out of the release notes:

https://codeberg.org/ziglang/zig/pulls/31349

Will correct that in a bit. EDIT: Added to the release notes

4 Likes

Very true. I will change that. Thanks for pointing out that detail.

(Most probably though I will have to skip a few zig-versions because of the disabled loop vectorization).

For what it’s worth:

const S = struct {
    value: u8 = 0,
};

test "unwrap null" {
    const maybe: ?*S = if (false) .{} else null;
    std.debug.print("\n{any}\n", .{@TypeOf(maybe)});
    // std.debug.print("{any}\n", .{maybe.?.value});
}

output:

1/15 root.test.unwrap null...
?*root.S
OK
test "unwrap null" {
    const maybe: ?*S = if (false) .{} else null;
    std.debug.print("\n{any}\n", .{@TypeOf(maybe)});
    std.debug.print("{any}\n", .{maybe.?.value});
}

output:

src/root.zig:24:39: error: unable to unwrap null
    std.debug.print("{any}\n", .{maybe.?.value});
                                 ~~~~~^~

In zig 0.15.2 output is:

?*root.S
thread 2742 panic: attempt to use null value
/home/gianmaria/Progetti/zig/libgm/src/root.zig:24:39: 0x102c011 in test.unwrap null 
(root.zig)
    std.debug.print("{any}\n", .{maybe.?.value});

so the compiler seems to be able to detect that a variable is always null at compile time and can’t be unwrapped. Still, the error message could be more informative because it’s surprising that you can’t unwrap an optional variable.

4 Likes

a comment on this,

  • IIRC, ‘f’ does not allow padding / alignment (which ‘D’ did) - you could work around by using `std.Io.Writer.alignBuffer`, here’s what I did in zbench: draft printer revision · hendriknielaender/zBench@71a5733 · GitHub
  • Side note: I find it irritating that ‘D’ and now ‘f’ output “years”, which is an ambiguous quantity at least for the Gregorian Calendar most of us are using.

Should be in orbits;sols… :wink:

full moon cycles, so we have a better feeling for how many werewolves to expect.