I’m very new to zig and have been going through ziglings. So far I think that Zig is the best thing since C. However, there is just one thing I am concerned about: Globals.
I was doing 029_errdefer when I noticed towards the end of the file:
// Sneaky, weird global stuff.
counter += 1;
And I thought to myself: Being able to define globals is great. By all means give me the gun that I will shoot my self in the foot with. But why make it so easy, or so opaque? In this instance the function is short so you can see there is no counter defined in the local context. But if it were at the end of a much longer function and the comment was not there it could cause needless headaches. I think accessing the global scope is rare, and in a language where standard practice is to be as verbose as:
std.debug.print("Hello world!")
It seems out of place to make accessing a global so simple. I would suggest requiring a keyword like this:
// Loud and proud weird global stuff.
global.counter += 1;
This way its obvious I’m using a global and I can even search for this keyword to find any usage of a specific global or globals in general.
I went on Github to file a feature request but it seems Zig is not accepting new language proposals. So I came here to lobby for a feature like this.
I hope its not too forward.
For reference here is a link to the complete ziglings excersize: ziglings/exercises/029_errdefer.zig at main · ratfactor/ziglings · GitHub
And below is the contents (incase it is deleted or changes)
//
// Another common problem is a block of code that could exit in multiple
// places due to an error - but that needs to do something before it
// exits (typically to clean up after itself).
//
// An "errdefer" is a defer that only runs if the block exits with an error:
//
// {
// errdefer cleanup();
// try canFail();
// }
//
// The cleanup() function is called ONLY if the "try" statement returns an
// error produced by canFail().
//
const std = @import("std");
var counter: u32 = 0;
const MyErr = error{ GetFail, IncFail };
pub fn main() void {
// We simply quit the entire program if we fail to get a number:
var a: u32 = makeNumber() catch return;
var b: u32 = makeNumber() catch return;
std.debug.print("Numbers: {}, {}\n", .{ a, b });
}
fn makeNumber() MyErr!u32 {
std.debug.print("Getting number...", .{});
// Please make the "failed" message print ONLY if the makeNumber()
// function exits with an error:
std.debug.print("failed!\n", .{});
var num = try getNumber(); // <-- This could fail!
num = try increaseNumber(num); // <-- This could ALSO fail!
std.debug.print("got {}. ", .{num});
return num;
}
fn getNumber() MyErr!u32 {
// I _could_ fail...but I don't!
return 4;
}
fn increaseNumber(n: u32) MyErr!u32 {
// I fail after the first time you run me!
if (counter > 0) return MyErr.IncFail;
// Sneaky, weird global stuff.
counter += 1;
return n + 1;
}
```zig