Nitpick Streams Architecture
Nitpick utilizes a powerful six-stream architecture that extends the traditional UNIX standard streams. This architecture provides dedicated channels for distinct types of data flow, ensuring clean separation of concerns for command-line tools and system services.
Six-Stream Architecture
| Stream | FD | Purpose | Default Behavior |
|---|---|---|---|
stdin |
0 | Text Input | Reads from console input or piped stdin |
stdout |
1 | Text Output | Writes to console output or piped stdout |
stderr |
2 | Error Output | Writes to console error output |
stddbg |
3 | Debug Output | Writes to stderr if FD 3 is not redirected |
stddati |
4 | Binary Data Input | Fails if FD 4 is not redirected |
stddato |
5 | Binary Data Output | Fails if FD 5 is not redirected |
The addition of stddbg, stddati, and stddato allows programs to cleanly separate diagnostic information from normal error reporting, and to handle binary payloads natively without polluting standard text streams.
Streams as First-Class Values
In Nitpick, streams are opaque handles represented by the int8-> type (or specific stream handles in the compiler's internal representation). They are first-class values and can be freely passed to or returned from functions.
Example: Custom Logger
You can write flexible functions that write to any target stream:
func:log_message = void(int8->:out_stream, string:level, string:msg) {
print(out_stream, `[&{level}] `);
println(out_stream, msg);
}
func:main = int32() {
// Log an error to stderr
log_message(stderr, "ERROR", "Failed to connect to database");
// Log debug information to the debug stream
log_message(stddbg, "DEBUG", "Connection retry attempt 1");
exit 0;
}
File Streams
In addition to the standard system streams, you can create new streams connected to files on disk.
Opening and Managing
File streams are opened using File.open(path, mode) where mode is "r", "w", or "a".
func:process_data = void() {
// Open stream
int8->:f = raw File.open("output.txt", "w");
// Use stream
File_write(f, "Processing complete.\\n");
// Manage lifecycle
File_flush(f);
File_close(f);
}
Stream Lifecycle
- Open: Acquire the handle using
File.open. - Use: Read/write data and manipulate the cursor with
File_seekandFile_tell. - Close: Always close your file streams with
File_closeto release system resources. The standard system streams (0-5) do not need to be closed.
Shell Redirection
The true power of the six-stream architecture becomes apparent when used in shell environments. You can independently redirect any of the six streams.
# Standard redirection
./my_program > output.txt 2> error.log
# Redirect debug stream (FD 3) to a separate file
./my_program 3> debug.log
# Read binary data from a file (FD 4) and write to stdout
./my_program 4< input.bin > output.txt
If stddbg (FD 3) is not redirected by the shell, Nitpick automatically falls back to printing debug output to stderr. This ensures debug messages are not lost when running interactively.