What is the purpose of allowing the creation of undefined constants?

Hello everyone,

I’m new to Zig, coming from a Java background. While reading the Zig guide, I came across the undefined keyword and how to use it.

It’s obvious that in certain situation we may need to create a variable, but not set the value immediately. However I don’t quite understand in what situation it would make sense to create an undefined constant, since we could never assign a value to it.

const x: u8 = undefined;
u8 = 42; // compilation error: cannot assign to constant

I would be grateful if anyone could help me with this conundrum!

Thanks

const x: u8 = undefined is declaring a const variable named x of type u8 with the initial value of undefined. A const variable cannot be assigned to after declaration.

u8 is a language defined type and will be const, so cannot be changed.

You can however declare your own variable with the value undefined and use it as a shorthand for undefined.

const und = undefined;
var x:u8 = und;

const x: u8 = undefined is declaring a const variable named x of type u8 with the initial value of undefined. A const variable cannot be assigned to after declaration.

u8 is a language defined type and will be const, so cannot be changed.

This is exactly my understanding, hence my confusion of allowing the creation of undefined constant.

I see your point of being able to create a global undefined constant, but in my personal opinion constants should always have an actual value, and the language should not allow to declare undefined constants, as I see it as a contradiction.

Anyway, thanks for sharing your thoughts @tobyjaffey!

1 Like

Comptime conditions could be a reason why you’d potentially want to ability to declare undefined constants.

const profiler: Profiler = if (builtin.mode = .ReleaseFast) try Profiler.init(allocator) else undefined;

// somewhere later
doStuff(..., profiler);
// doStuff() does its thing and independently checks the same comptime condition;
// ends up not using the argument even though its signature still requires it

It’s a contrived example, of course, since you’d ideally avoid this kind of situations. They might happen with code you cannot control, however, where you know for a fact e.g. an FFI library won’t use a parameter so you pass undefined, but you want to give it a name through const to improve readability. (Relevant because Zig doesn’t have /* block comments */ meaning you cannot just put the parameter name inline like foo(/* bar, unused */ undefined);.

Another, even more contrived situation where you’d want a global const value could be to pad the size of the uninitialized section in the resulting executable, e.g. so that other constants or variables appear at a particular address. With ASLR and similar techniques being widespread this use case should be very rare, but it could conceivably arise on some embedded platforms.

Thanks @Xion! I’m starting to understand why declaring undefined constants make actual sense, instead of seeing it as a contradiction.

In my work experience, over the last two decades and especially in Java, I never had to deal with FFI libraries and anything low level. So all this is completely new! Which is great, because I like learning new things and get better in what I do.

1 Like

Technically in the future they want to disallow all unused values, (imports,constant etc.) so in the future because the compiler doesn’t allow you to read the value and as such you actually can’t use the constant, it will be an error, but right now it’s not the case :slight_smile:

3 Likes

Thank you for giving further details on this topic @pierrelgol.

1 Like
// somewhere later
doStuff(..., profiler);
// doStuff() does its thing and independently checks the same comptime condition;
// ends up not using the argument even though its signature still requires it

I want to emphasize the comment. In this example you must recheck the condition, as you can’t check if something is undefined (otherwise it could be defined). So you could do this where the computation is expensive and you only want to do it once, but the check is cheap and you are ok with doing it multiple times.

An alternative, though not directly equal, would be to set the value to be of type void at comptime, if the condition fails, which means it would just not exist (think a #ifdef macro in c). I think you would even get a compilation error in that case.

Thanks for the clarification @Calder-Ty. The subject of declaring and using undefined constants is a lot deeper than I thought!

It seem to be compile error soon Proposal: remove `std.builtin.Type.undefined`; the expression `undefined` requires a result type · Issue #22710 · ziglang/zig · GitHub

1 Like

Boo! :grinning:

I used const u = undefined to let me write shorter code in obfusgator/obfusgator.zig at main · ringtailsoftware/obfusgator · GitHub

Probably serves as a good example of why this should not be allowed

4 Likes

Sounds more like a security feature/job guarantee when you put it like that :smirk: