summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Boesch <chrboesch@noreply.codeberg.org>2026-04-12 17:28:37 +0200
committerChris Boesch <chrboesch@noreply.codeberg.org>2026-04-12 17:28:37 +0200
commit8e055fcd187b333c9ed4fa794ac153ed10748a65 (patch)
tree6ddfb7595700feccda672cd859ed077a3c06b258
parentb225538aed949c50559e37f137663008539fcdee (diff)
parent2472caa18377d36d68c5c5b5989726d2df783866 (diff)
Merge pull request 'Replace exercise 074_comptime9' (#391) from tjk/ziglings-exercises:comptime9 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/391
-rw-r--r--build.zig2
-rw-r--r--exercises/074_comptime9.zig149
-rw-r--r--patches/patches/074_comptime9.patch42
3 files changed, 133 insertions, 60 deletions
diff --git a/build.zig b/build.zig
index 9209848..eaaefe6 100644
--- a/build.zig
+++ b/build.zig
@@ -1075,7 +1075,7 @@ const exercises = [_]Exercise{
},
.{
.main_file = "074_comptime9.zig",
- .output = "My llama value is 2.",
+ .output = "MouseLlama joins the crew!",
},
.{
.main_file = "075_quiz8.zig",
diff --git a/exercises/074_comptime9.zig b/exercises/074_comptime9.zig
index 4088aad..50894fd 100644
--- a/exercises/074_comptime9.zig
+++ b/exercises/074_comptime9.zig
@@ -1,62 +1,111 @@
+const print = @import("std").debug.print;
+
+// We're going to (ab)use the power of Zig to make animal hybrid creatures!
+// What do you think a GatorMouse would look like? Eek.
//
-// In addition to knowing when to use the 'comptime' keyword,
-// it's also good to know when you DON'T need it.
-//
-// The following contexts are already IMPLICITLY evaluated at
-// compile time, and adding the 'comptime' keyword would be
-// superfluous, redundant, and smelly:
-//
-// * The container-level scope (outside of any function in a source file)
-// * Type declarations of:
-// * Variables
-// * Functions (types of parameters and return values)
-// * Structs
-// * Unions
-// * Enums
-// * The test expressions in inline for and while loops
-// * An expression passed to the @cImport() builtin
-//
-// Work with Zig for a while, and you'll start to develop an
-// intuition for these contexts. Let's work on that now.
-//
-// You have been given just one 'comptime' statement to use in
-// the program below. Here it is:
-//
-// comptime
-//
-// Just one is all it takes. Use it wisely!
+// Let's try a MouseLlama instead.
//
-const print = @import("std").debug.print;
+// We'll make a function that runs at comptime and takes a short code describing
+// the desired creature. A Mouse is represented by "m" and a Llama is "lm".
+// A MouseLlama hybrid, then, would be represented by "mlm".
+
+const Animal = enum {
+ Mouse,
+ Llama,
+ Gator,
+};
+
+// makeCreature takes the count of animals making up the hybrid creature (so we
+// know how big a pen we'll need) and a format string, like the "mlm" for
+// MouseLlama.
+fn makeCreature(comptime count: usize, comptime fmt: []const u8) [count]Animal {
+
+ // Since not every animal is represented by a single character, we need to
+ // track the state of things as we move along. For example, if we see an
+ // "m", is that a new Mouse or the end of a Llama?
+ const State = enum {
+ start, // Ready to start a new animal.
+ l, // This means we've seen an "l", so if we see an "m", we know it's a Llama.
+ };
+ var state = State.start;
-// Being in the container-level scope, everything about this value is
-// implicitly required to be known compile time.
-const llama_count = 5;
+ // We return an array of animals representing the creature. (This is why we
+ // really needed the 'count' parameter. Arrays need a size.)
+ var animals: [count]Animal = .{undefined} ** count;
+ var next_animal: usize = 0;
-// Again, this value's type and size must be known at compile
-// time, but we're letting the compiler infer both from the
-// return type of a function.
-const llamas = makeLlamas(llama_count);
+ inline for (fmt) |char| {
-// And here's the function. Note that the return value type
-// depends on one of the input arguments!
-fn makeLlamas(count: usize) [count]u8 {
- var temp: [count]u8 = undefined;
- var i = 0;
+ // This is a good spot to add a @compileLog() call if you need to debug
+ // any variables... (Come back here after you see main().)
- // Note that this does NOT need to be an inline 'while'.
- while (i < count) : (i += 1) {
- temp[i] = i;
+ switch (state) {
+ .start => switch (char) {
+ // We've seen the start of a Llama.
+ 'l' => state = .l,
+
+ // Mice are smaller. An "m" is a full Mouse.
+ 'm' => {
+ animals[next_animal] = .Mouse;
+ next_animal += 1;
+ },
+
+ // @compileError lets us stop the build immediately if something
+ // is wrong. It's like @compileLog but it prints a message
+ // instead of inspecting values.
+ //
+ // What do you think happens with Gators? Do they join with
+ // other animals or is this an error?
+ 'g' => ???,
+
+ else => @compileError("No animal starts with '" ++ char ++ "'!"),
+ },
+
+ .l => switch (char) {
+ // We've seen the end of a Llama.
+ 'm' => {
+ animals[next_animal] = .Llama;
+ next_animal += 1;
+ // Something is missing here. After we finish a Llama, we
+ // need to be ready to _start_ over with a new animal...
+ ???
+ },
+
+ else => @compileError("Only llamas start with 'l'!"),
+ },
+ }
}
- return temp;
+ if (state != .start) {
+ @compileError("Oh no, an incomplete llama!");
+ }
+ if (next_animal != count) {
+ @compileError("Creature is missing an animal (format string too short).");
+ }
+
+ return animals;
}
pub fn main() void {
- print("My llama value is {}.\n", .{llamas[2]});
+ // Once you've fixed the ??? marks above, this makeCreature call will still
+ // only succeed if you move it outside of main, so it will run at comptime.
+ //
+ // With the call here, Zig will try to make the creature at runtime, and
+ // you'll get an interesting error.
+ //
+ // You may think the state got mixed up, but if you use @compileLog to check
+ // some variables in makeCreature, you'll see that Zig is trying to compare
+ // comptime values with "[runtime value]", which will never match.
+ //
+ // You can solve this by adding "comptime" to two of the variables in
+ // makeCreature...
+ const creature = makeCreature(2, "mlm");
+
+ for (creature) |animal| {
+ // @tagName gives us a string representing which variant of an enum we
+ // have. This lets us print the names of animals without repeating them
+ // here.
+ print("{s}", .{@tagName(animal)});
+ }
+ print(" joins the crew!", .{});
}
-//
-// The lesson here is to not pepper your program with 'comptime'
-// keywords unless you need them. Between the implicit compile
-// time contexts and Zig's aggressive evaluation of any
-// expression it can figure out at compile time, it's sometimes
-// surprising how few places actually need the keyword.
diff --git a/patches/patches/074_comptime9.patch b/patches/patches/074_comptime9.patch
index 250d003..44a1709 100644
--- a/patches/patches/074_comptime9.patch
+++ b/patches/patches/074_comptime9.patch
@@ -1,11 +1,35 @@
---- exercises/074_comptime9.zig 2023-10-03 22:15:22.125574535 +0200
-+++ answers/074_comptime9.zig 2023-10-05 20:04:07.176102462 +0200
-@@ -39,7 +39,7 @@
+--- exercises/074_comptime9.zig 2026-04-11 21:35:08.132459373 -0700
++++ answers/074_comptime9.zig 2026-04-12 07:13:37.971010827 -0700
+@@ -27,12 +27,12 @@
+ start, // Ready to start a new animal.
+ l, // This means we've seen an "l", so if we see an "m", we know it's a Llama.
+ };
+- var state = State.start;
++ comptime var state = State.start;
- // And here's the function. Note that the return value type
- // depends on one of the input arguments!
--fn makeLlamas(count: usize) [count]u8 {
-+fn makeLlamas(comptime count: usize) [count]u8 {
- var temp: [count]u8 = undefined;
- var i = 0;
+ // We return an array of animals representing the creature. (This is why we
+ // really needed the 'count' parameter. Arrays need a size.)
+ var animals: [count]Animal = .{undefined} ** count;
+- var next_animal: usize = 0;
++ comptime var next_animal: usize = 0;
+ inline for (fmt) |char| {
+
+@@ -56,7 +56,7 @@
+ //
+ // What do you think happens with Gators? Do they join with
+ // other animals or is this an error?
+- 'g' => ???,
++ 'g' => @compileError("Gators refuse to join with other animals."),
+
+ else => @compileError("No animal starts with '" ++ char ++ "'!"),
+ },
+@@ -68,7 +68,7 @@
+ next_animal += 1;
+ // Something is missing here. After we finish a Llama, we
+ // need to be ready to _start_ over with a new animal...
+- ???
++ state = .start;
+ },
+
+ else => @compileError("Only llamas start with 'l'!"),