Chapter 19: Variations in Control Flow
Level 3 -- Experience
Non-local jumps, signals, and structured error handling -- understanding C's control flow escape hatches and how Auto replaces them with safer patterns.
Programs don't always follow a straight-line path. Functions return early, loops break out, errors propagate through call stacks. C provides several mechanisms for non-standard control flow: goto, setjmp/longjmp, and signal handlers. These are powerful but dangerous. Auto replaces most of them with structured alternatives.
19.1 A Detailed Example
Consider a parser that must handle errors at multiple levels:
// C Deep Dive: error handling with goto
#include <stdio.h>
#include <stdlib.h>
int parse_input(const char *input) {
if (!input) goto error_null;
if (*input == '\0') goto error_empty;
int value = atoi(input);
if (value <= 0) goto error_negative;
printf("Parsed: %d\n", value);
return value;
error_null:
fprintf(stderr, "Error: null input\n");
return -1;
error_empty:
fprintf(stderr, "Error: empty input\n");
return -2;
error_negative:
fprintf(stderr, "Error: non-positive value\n");
return -3;
}C programmers use goto for centralized error cleanup. It is one of the few accepted uses of goto in C. The pattern is: jump to a label that releases resources and reports the error.
Auto's approach. Auto uses Result types for error propagation:
// Auto: Result type for structured error handling
type ParseResult {
value int
ok bool
error str
}
fn ParseResult.ok(val int) ParseResult {
ParseResult(val, true, "")
}
fn ParseResult.err(msg str) ParseResult {
ParseResult(0, false, msg)
}
fn parse_input(input str) ParseResult {
if input == "" {
return ParseResult.err("empty input")
}
let value int = int(input)
if value <= 0 {
return ParseResult.err("non-positive value")
}
ParseResult.ok(value)
}