diff --git a/content/posts/learning-zig--day-2.md b/content/posts/learning-zig--day-2.md new file mode 100644 index 0000000..3a5e6b3 --- /dev/null +++ b/content/posts/learning-zig--day-2.md @@ -0,0 +1,152 @@ ++++ +categories = ["zig"] +date = 2021-05-15 +description = "Onwards in our quest to learn Zig" +slug = "learning-zig--day-2" +tags = ["zig", "learn"] +title = "Learning Zig - Day 2" ++++ + +In the [previous post] I documented how I went about setting up my Zig environment, and it's now time to start learning things. + +My preferred method of learning new languages is rebuilding an existing project in them, like I did when going from [Python] to [Kotlin] to [Rust]. For Zig, I've elected to rebuild my [healthchecks-rs] library. It's something I use on a day-to-day basis for keeping an eye on my backup jobs, and it would be a great addition to the [healthchecks.io ecosystem]. + + +# Getting the basics down + +Among the resources enlisted on the Zig [getting started] page, I opted to go with [ziglearn.org] for learning the ropes of the language. It is concise yet detailed, and the chapter-wise breakdown makes for great mental "checkpoints", much like the [Rust book]. + + +For this post I'm going through [chapter 1]. + +# Thoughts™️ + +I'm going to use this section to jot down my thoughts about Zig, broken down by the sections on ZigLearn. I'll skip the parts that I don't have anything to say on. + +## Assignment + +The presence of `undefined` is *very* interesting to me. It appears to be functionally identical to Rust's [Default trait], as shown in this snippet (had to skip to structs for this since I was so curious about it). + +```zig +const std = @import("std"); + +const Vec3 = struct { + x: f32, + y: f32, + z: f32, +}; + +pub fn main() void { + const inferred_constant: Vec3 = undefined; + std.debug.print("Hello, {d}!\n", .{inferred_constant}); +} +``` + +which prints: + +``` +➜ zig build run +Hello, Vec3{ .x = 0, .y = 0, .z = 0 }! +``` + +I have clearly not gotten very far yet, but initial thoughts here: Rust's trait-based implementation means I can customize the "default" values for my structs, which I'm not seeing in this implicit coercion yet. Guess we'll find out soon whether or not this can be handled explicitly :D + +## Arrays + +The syntax for array declarations is quite clear and explicit, which I like. Notably, while you can do this: + +```zig +const implicitly_sized_array = [_]u8{}; // _ means "infer the size" +``` + +you cannot have an inferred size reference as the type: + +```zig +const implicitly_sized_array[_]u8 = {}; +``` + +Rust also [disallows this](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f27a1a0b20feebe3e6d0a3417f25ce45), but the error is surprisingly worse than with Zig. Rust's resident diagnostics magician Esteban [assures me](https://twitter.com/ekuber/status/1393566561005314048) this is a regression and is being tracked. + + +The only problem I encountered here was that I can't figure out how to print an array! + +```zig +const implicitly_sized_array = [_]u8{0, 1, 2, 3}; +std.debug.print("This is an array: {}\n", .{implicitly_sized_array}); + +// Outputs: "This is an array: " +``` + +I found a [PR that overhauls formatting] but nothing there gave me any pointers on why my code doesn't work. Hopefully this'll get cleared up later. + +## If + +Nothing special here, aside from the early introduction to testing, which is slightly more pleasant than with Rust. I do however have qualms about the test output, which is unnecessarily noisy: + +```shell +Test [2/2] test "while with continue expression"... expected 2080, found 10 +/nix/store/nhd75c4sr3l9wlaspilkwawx5ixkn74w-zig-0.7.1/lib/zig/std/testing.zig:74:32: 0x206f9a in std.testing.expectEqual (test) + std.debug.panic("expected {}, found {}", .{ expected, actual }); + ^ +/home/msfjarvis/git-repos/zig-playground/src/main.zig:29:24: 0x205abd in test "while with continue expression" (test) + testing.expectEqual(sum, 10); + ^ +/nix/store/nhd75c4sr3l9wlaspilkwawx5ixkn74w-zig-0.7.1/lib/zig/std/special/test_runner.zig:61:28: 0x22e161 in std.special.main (test) + } else test_fn.func(); + ^ +/nix/store/nhd75c4sr3l9wlaspilkwawx5ixkn74w-zig-0.7.1/lib/zig/std/start.zig:334:37: 0x20749d in std.start.posixCallMainAndExit (test) + const result = root.main() catch |err| { + ^ +/nix/store/nhd75c4sr3l9wlaspilkwawx5ixkn74w-zig-0.7.1/lib/zig/std/start.zig:162:5: 0x2071d2 in std.start._start (test) + @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); + ^ +error: the following test command crashed: +./src/zig-cache/o/5a647f3d3394214b30b3861a6b0ffbbb/test +``` + +## Defer + +The `defer` language feature is something I've always been curious about since seeing it in Go, so I'm excited to discover use-cases for it when I finally have it available. Through ZigLearn I discovered that `defer` calls can be stacked to be executed in LIFO order, and Golang does it in the exact same fashion. + +## Errors + +I like how easy it is to define errors, but the syntax feels kinda icky. Having each error enum I declare 'magically' become a property on the `error` keyword doesn't sit right with me :( + +```zig +const NumericError = error{}; + +fn mayError(shouldError: bool) anyerror!u32 { + return if (shouldError) + // This is different from what I'm accustomed to as a user of + // Either/Result type monads. + error.NumericError + else + 10; +} +``` + +## Runtime Safety + +Being able to turn off runtime safety features (like bounds checking) in specific blocks is pretty interesting! Not sure if I'll ever have a valid use for it though... + + +## Conclusion + +I like most of what I've seen so far in Zig. Aside from the issues I mentioned above, the lack of string type is a very confusing thing for me. I've kinda come to expect it everywhere based on my previous experiences with Python, Java, Kotlin, and Rust; but maybe I'll now learn to appreciate how every character on my screen is just numbers :D. + +I was very easily distracted today, so I only made it a third of the way in 3 hours for a chapter that is supposed to take 1 hour for the whole thing. Hoping to finish it tomorrow! + + +[previous post]: /posts/first-steps-with-zig +[Python]: https://msfjarvis.dev/g/walls-manager +[Kotlin]: https://msfjarvis.dev/g/walls-bot +[Rust]: https://msfjarvis.dev/g/walls-bot-rs +[healthchecks-rs]: https://msfjarvis.dev/g/healthchecks-rs +[healthchecks.io ecosystem]: https://healthchecks.io/docs/resources/ +[getting started]: https://ziglang.org/learn/getting-started/ +[ziglearn.org]: https://ziglearn.org/ +[Rust book]: https://doc.rust-lang.org/book/ +[chapter 1]: https://ziglearn.org/chapter-1/ +[Default trait]: https://doc.rust-lang.org/std/default/trait.Default.html +[PR that overhauls formatting]: https://github.com/ziglang/zig/pull/6870 +[`unreachable`]: https://ziglearn.org/chapter-1/#unreachable