From 1c6487c1e79cbe0d59a39b483af8ec44b59c586e Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 3 Apr 2026 18:11:00 +0200 Subject: added async-io quiz --- exercises/084_interfaces.zig | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 exercises/084_interfaces.zig (limited to 'exercises/084_interfaces.zig') diff --git a/exercises/084_interfaces.zig b/exercises/084_interfaces.zig new file mode 100644 index 0000000..7775dd5 --- /dev/null +++ b/exercises/084_interfaces.zig @@ -0,0 +1,127 @@ +// +// Remember our ant and bee simulator constructed with unions +// back in exercises 55 and 56? There, we demonstrated that +// unions allow us to treat different data types in a uniform +// manner. +// +// One neat feature was using tagged unions to create a single +// function to print a status for ants *or* bees by switching: +// +// switch (insect) { +// .still_alive => ... // (print ant stuff) +// .flowers_visited => ... // (print bee stuff) +// } +// +// Well, that simulation was running just fine until a new insect +// arrived in the virtual garden, a grasshopper! +// +// Doctor Zoraptera started to add grasshopper code to the +// program, but then she backed away from her keyboard with an +// angry hissing sound. She had realized that having code for +// each insect in one place and code to print each insect in +// another place was going to become unpleasant to maintain when +// the simulation expanded to hundreds of different insects. +// +// Thankfully, Zig has another comptime feature we can use +// to get out of this dilemma called the 'inline else'. +// +// We can replace this redundant code: +// +// switch (thing) { +// .a => |a| special(a), +// .b => |b| normal(b), +// .c => |c| normal(c), +// .d => |d| normal(d), +// .e => |e| normal(e), +// ... +// } +// +// With: +// +// switch (thing) { +// .a => |a| special(a), +// inline else => |t| normal(t), +// } +// +// We can have special handling of some cases and then Zig +// handles the rest of the matches for us. +// +// With this feature, you decide to make an Insect union with a +// single uniform 'print()' function. All of the insects can +// then be responsible for printing themselves. And Doctor +// Zoraptera can calm down and stop gnawing on the furniture. +// +const std = @import("std"); + +const Ant = struct { + still_alive: bool, + + pub fn print(self: Ant) void { + std.debug.print("Ant is {s}.\n", .{if (self.still_alive) "alive" else "dead"}); + } +}; + +const Bee = struct { + flowers_visited: u16, + + pub fn print(self: Bee) void { + std.debug.print("Bee visited {} flowers.\n", .{self.flowers_visited}); + } +}; + +// Here's the new grasshopper. Notice how we've also added print +// methods to each insect. +const Grasshopper = struct { + distance_hopped: u16, + + pub fn print(self: Grasshopper) void { + std.debug.print("Grasshopper hopped {} meters.\n", .{self.distance_hopped}); + } +}; + +const Insect = union(enum) { + ant: Ant, + bee: Bee, + grasshopper: Grasshopper, + + // Thanks to 'inline else', we can think of this print() as + // being an interface method. Any member of this union with + // a print() method can be treated uniformly by outside + // code without needing to know any other details. Cool! + pub fn print(self: Insect) void { + switch (self) { + inline else => |case| return case.print(), + } + } +}; + +pub fn main() !void { + const my_insects = [_]Insect{ + Insect{ .ant = Ant{ .still_alive = true } }, + Insect{ .bee = Bee{ .flowers_visited = 17 } }, + Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 } }, + }; + + std.debug.print("Daily Insect Report:\n", .{}); + for (my_insects) |insect| { + // Almost done! We want to print() each insect with a + // single method call here. + ??? + } +} + +// Our print() method in the Insect union above demonstrates +// something very similar to the object-oriented concept of an +// abstract data type. That is, the Insect type doesn't contain +// the underlying data, and the print() function doesn't +// actually do the printing. +// +// The point of an interface is to support generic programming: +// the ability to treat different things as if they were the +// same to cut down on clutter and conceptual complexity. +// +// The Daily Insect Report doesn't need to worry about *which* +// insects are in the report - they all print the same way via +// the interface! +// +// Doctor Zoraptera loves it. -- cgit v1.2.3 From f6a6798c8b6b813bd2ceee81db276e05327a76e0 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 3 Apr 2026 19:28:12 +0200 Subject: improved report design --- build.zig | 2 +- exercises/084_interfaces.zig | 2 +- patches/patches/084_interfaces.patch | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'exercises/084_interfaces.zig') diff --git a/build.zig b/build.zig index 7bde273..d3d91ee 100644 --- a/build.zig +++ b/build.zig @@ -1121,7 +1121,7 @@ const exercises = [_]Exercise{ .{ .main_file = "084_interfaces.zig", .output = - \\Daily Insect Report: + \\=== Doctor Zoraptera's Insect Report === \\Ant is alive. \\Bee visited 17 flowers. \\Grasshopper hopped 32 meters. diff --git a/exercises/084_interfaces.zig b/exercises/084_interfaces.zig index 7775dd5..fd61ead 100644 --- a/exercises/084_interfaces.zig +++ b/exercises/084_interfaces.zig @@ -102,7 +102,7 @@ pub fn main() !void { Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 } }, }; - std.debug.print("Daily Insect Report:\n", .{}); + std.debug.print("=== Doctor Zoraptera's Insect Report ===\n", .{}); for (my_insects) |insect| { // Almost done! We want to print() each insect with a // single method call here. diff --git a/patches/patches/084_interfaces.patch b/patches/patches/084_interfaces.patch index a1d0628..d3a45fd 100644 --- a/patches/patches/084_interfaces.patch +++ b/patches/patches/084_interfaces.patch @@ -1,5 +1,5 @@ ---- exercises/084_interfaces.zig 2025-08-15 15:17:57.839348063 +0200 -+++ answers/084_interfaces.zig 2026-04-03 14:27:32.670756488 +0200 +--- exercises/084_interfaces.zig 2026-04-03 19:24:51.764327692 +0200 ++++ answers/084_interfaces.zig 2026-04-03 19:27:31.552579474 +0200 @@ -106,7 +106,7 @@ for (my_insects) |insect| { // Almost done! We want to print() each insect with a -- cgit v1.2.3