Reading a filled nullable

A snippet from my chess program:
I have a nullable eval variable which is only filled if not is_check.

We know eval is filled when is_check is false.
Is using eval.? the best way to code it?

Does it have any performance implications to read eval.? instead of a raw int (in release mode)?

const eval: ?i32 = if (is_check) null else evaluate(); // correct edited example

// const eval: i32 = if (!is_check) null else evaluate(); // wrong first example

// ...
// lots of code in between.
// ...
if (!is_check and some_other_conditions) {
    if (eval.? == 42) { do something }
}

if (!is_check and more_conditions) {
    if (eval.? == 43) { do something }
}

Yes, that’s the intended use-case for foo.?.

From the language reference:

Equivalent to:

a orelse unreachable

(so it allows the compiler to optimize based on your guarantee that the value will never be null at that point)

9 Likes

I’d also consider this:

const eval: i32 = if (!is_check) undefined else evaluate();
// ...
// lots of code in between.
// ...
if (!is_check and some_other_conditions) {
    if (eval == 42) { do something }
}

if (!is_check and more_conditions) {
    if (eval == 43) { do something }
}

That way you don’t have to bother with unwrapping eval everywhere you need it and still get a runtime crash in safe modes if you accidentaly try to access eval anywhere you shouldn’t because it’ll be undefined.

3 Likes

True for a local as in the example.
However these evals are stored in a big stack of nodes and reused so I stick with nullable.
(To explain: when going deeper into the search-tree i compare current evals with previous evals (if available) to check improvement)

1 Like

Not to nitpick, but is your first line backwards? Feels like you want to set eval to null when is_check.

2 Likes

Did you mean ?i32?

1 Like

No it’d have to be ?i32 in the original snippet but i32 can be undefined (just like any other value)

YES. I will change it

1 Like

I am failing to crash my program. What am I doing wrong?

var runtime_known = false;
runtime_known = !runtime_known;
const foo: i32 = if (runtime_known) undefined else 69;
if (foo == 42) {
    std.debug.print("==42: {}\n", .{ foo });
}
if (foo != 43) {
    std.debug.print("!=43: {}\n", .{ foo });
}

Output:

!=43: 1

It does not crash. It just uses garbage value.

P.S. I wonder why the garbage is not 0xAA pattern.

1 Like

Yeah sorry you’re right. That would be #211.
I also find it weird that the value is not 0xAA though, it’s 0 for me. This:

    var foo: i32 = undefined;
    if (!runtime_known) foo = 69;

does set foo to 0xAA so it might be a bug that your version doesn’t.

1 Like

Confirmed

2 Likes