diff --git a/build.zig b/build.zig index 410da75..fe80a3e 100644 --- a/build.zig +++ b/build.zig @@ -340,6 +340,10 @@ const exercises = [_]Exercise{ .main_file = "067_comptime2.zig", .output = "A BB CCC DDDD", }, + .{ + .main_file = "068_comptime3.zig", + .output = "Minnow (1:32, 4 x 2)\nShark (1:16, 8 x 5)\nWhale (1:1, 143 x 95)\n", + }, }; /// Check the zig version to make sure it can compile the examples properly. diff --git a/exercises/068_comptime3.zig b/exercises/068_comptime3.zig new file mode 100644 index 0000000..ebe6c8f --- /dev/null +++ b/exercises/068_comptime3.zig @@ -0,0 +1,108 @@ +// +// You can also put 'comptime' before a function parameter to +// enforce that the argument passed to the function must be known +// at compile time. We've actually been using a function like +// this the entire time, std.debug.print(): +// +// fn print(comptime fmt: []const u8, args: anytype) void +// +// Notice that the format string parameter 'fmt' is marked as +// 'comptime'. One of the neat benefits of this is that the +// format string can be checked for errors at compile time rather +// than crashing at runtime. +// +// (The actual formatting is done by std.fmt.format() and it +// contains a complete format string parser that runs entirely at +// compile time!) +// +const print = @import("std").debug.print; + +// This struct is the model of a model boat. We can transform it +// to any scale we would like: 1:2 is half-size, 1:32 is +// thirty-two times smaller than the real thing, and so forth. +const Schooner = struct { + name: []const u8, + scale: u32 = 1, + hull_length: u32 = 143, + bowsprit_length: u32 = 34, + mainmast_height: u32 = 95, + + fn scaleMe(self: *Schooner, comptime scale: u32) void { + var my_scale = scale; + + // We did something neat here: we've anticipated the + // possibility of accidentally attempting to create a + // scale of 1:0. Rather than having this result in a + // divide-by-zero error at runtime, we've turned this + // into a compile error. + // + // This is probably the correct solution most of the + // time. But our model boat model program is very casual + // and we just want it to "do what I mean" and keep + // working. + // + // Please change this so that it sets a 0 scale to 1 + // instead. + if (my_scale == 0) @compileError("Scale 1:0 is not valid!"); + + self.scale = my_scale; + self.hull_length /= my_scale; + self.bowsprit_length /= my_scale; + self.mainmast_height /= my_scale; + } + + fn printMe(self: Schooner) void { + print("{s} (1:{}, {} x {})\n", .{ + self.name, + self.scale, + self.hull_length, + self.mainmast_height, + }); + } +}; + +pub fn main() void { + var whale = Schooner {.name = "Whale"}; + var shark = Schooner {.name = "Shark"}; + var minnow = Schooner {.name = "Minnow"}; + + // Hey, we can't just pass this runtime variable as an + // argument to the scaleMe() method. What would let us do + // that? + var scale: u32 = undefined; + + scale = 32; // 1:32 scale + + minnow.scaleMe(scale); + minnow.printMe(); + + scale -= 16; // 1:16 scale + + shark.scaleMe(scale); + shark.printMe(); + + scale -= 16; // 1:0 scale (oops, but DON'T FIX THIS!) + + whale.scaleMe(scale); + whale.printMe(); +} +// +// Going deeper: +// +// What would happen if you DID attempt to build a model in the +// scale of 1:0? +// +// A) You're already done! +// B) You would suffer a mental divide-by-zero error. +// C) You would construct a singularity and destroy the +// planet. +// +// And how about a model in the scale of 0:1? +// +// A) You're already done! +// B) You'd arrange nothing carefully into the form of the +// original nothing but infinitely larger. +// C) You would construct a singularity and destroy the +// planet. +// +// Answers can be found on the back of the Ziglings packaging. diff --git a/patches/patches/068_comptime3.patch b/patches/patches/068_comptime3.patch new file mode 100644 index 0000000..985f0e6 --- /dev/null +++ b/patches/patches/068_comptime3.patch @@ -0,0 +1,8 @@ +46c46 +< if (my_scale == 0) @compileError("Scale 1:0 is not valid!"); +--- +> if (my_scale == 0) my_scale = 1; //@compileError("Scale 1:0 is not valid!"); +72c72 +< var scale: u32 = undefined; +--- +> comptime var scale: u32 = undefined;