Skip to content

Exercises

1. Write a function parseUpper that accepts a byte and returns the uppercase letter value. Return error.InvalidUppercase if the byte is not between 'A' and 'Z'.

  1. Write a function parseUpper that accepts a byte and returns the uppercase letter value. Return error.InvalidUppercase if the byte is not between 'A' and 'Z'.
fn parseUpper(c: u8) !u8 {
    // ...
}
  1. Write a function safeDivide that divides two integers. Return error.DivisionByZero when the divisor is zero.
fn safeDivide(a: u32, b: u32) !u32 {
    // ...
}
  1. Write a function first that returns the first byte of a slice. Return error.EmptySlice if the slice is empty.
fn first(s: []const u8) !u8 {
    // ...
}
  1. Write a function last that returns the last byte of a slice.

  2. Write a function requirePositive that returns error.NegativeNumber if its argument is less than zero.

  3. Rewrite this code using try:

const value = parseNumber(text) catch |err| return err;
  1. Rewrite this code using catch:
const value = try parseNumber(text);
  1. Write a function parseTwoDigits that parses two ASCII digits into a number between 0 and 99.
try parseTwoDigits('4', '2') // 42
  1. Write a function that opens a file and closes it with defer.

  2. Allocate memory with an allocator and release it with defer.

  3. Allocate memory and return it from a function. Use errdefer so that memory is freed only on failure.

  4. Write a function that translates error.FileNotFound into error.MissingConfig.

  5. Write a program that reads a filename from the command line and prints a clear error message if opening the file fails.

  6. Write a parser that never prints errors directly. Handle all printing in main.

  7. Write a function that parses an integer from a byte slice and returns:

ErrorMeaning
error.EmptyInputslice is empty
error.InvalidDigitnon-digit found
error.Overflowvalue does not fit
  1. Write a function that reads a file into memory using:
  • readFileAlloc
  • defer
  • try
  • catch
  1. Write a function that creates two resources and releases them in reverse order using multiple defer statements.

  2. Modify a previous program so that all resource cleanup is handled by defer and all error propagation uses try.

  3. Write a small command-line calculator:

calc 10 / 2
5

calc 10 / 0
error: DivisionByZero
  1. Write a program that loads a configuration file and applies these rules:
FailureBehavior
file missinguse defaults
invalid configprint error and stop
out of memoryreturn error immediately
  1. Write a function that retries a failing operation three times before returning the final error.

  2. Write a small library with public functions that return explicit error sets.

  3. Write a wrapper function that converts low-level filesystem errors into application-level errors.

  4. Review a previous chapter program and identify:

  • where try should be used
  • where catch should be used
  • where defer belongs
  • where errdefer belongs
  • where the program boundary should handle errors
  1. Write a complete program that:
  • reads a file
  • parses integers from it
  • allocates memory dynamically
  • handles malformed input
  • frees all resources correctly
  • prints useful error messages only at the outer boundary

This chapter introduced four central ideas:

FeaturePurpose
error setsdescribe failure
error unionscombine values and errors
trypropagate failure
catchhandle failure
deferguaranteed cleanup
errdefercleanup only on error

These appear throughout Zig programs. Most library APIs use them directly, and most real programs depend on them for resource management and control flow.