summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--build.zig4
-rw-r--r--exercises/092_interfaces.zig127
-rw-r--r--patches/patches/092_interfaces.patch4
3 files changed, 135 insertions, 0 deletions
diff --git a/build.zig b/build.zig
index 930fc56..4fa8a1d 100644
--- a/build.zig
+++ b/build.zig
@@ -462,6 +462,10 @@ const exercises = [_]Exercise{
// .@"async" = true,
// },
.{
+ .main_file = "092_interfaces.zig",
+ .output = "Daily Insect Report:\nAnt is alive.\nBee visited 17 flowers.\nGrasshopper hopped 32 meters.",
+ },
+ .{
.main_file = "999_the_end.zig",
.output = "\nThis is the end for now!\nWe hope you had fun and were able to learn a lot, so visit us again when the next exercises are available.",
},
diff --git a/exercises/092_interfaces.zig b/exercises/092_interfaces.zig
new file mode 100644
index 0000000..43f1119
--- /dev/null
+++ b/exercises/092_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 dilema 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
+ // 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 {
+ var 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.
diff --git a/patches/patches/092_interfaces.patch b/patches/patches/092_interfaces.patch
new file mode 100644
index 0000000..1287e79
--- /dev/null
+++ b/patches/patches/092_interfaces.patch
@@ -0,0 +1,4 @@
+109c109
+< ???
+---
+> insect.print();