In Zig 0.16, we now have juicy main via std.process.Init.
This structure provides common process plumbing (I/O, allocator, environment, etc.) to make it easier to start writing programs.
I think it would also be reasonable to include a non-cryptographic PRNG provider in Init.
A very common need for new users—and for many small, quick command-line tools—is simply “I need random numbers”. Today this requires several lines of setup (OS randomness + seeding + PRNG selection), which feels heavy for simple use cases.
I am not proposing a global RNG stream, nor cryptographic randomness.
The idea is to provide a factory-style interface that returns a fast PRNG, with explicit seeding.
Proposed user-side usage
const std = @import("std");
pub fn main(init: std.process.Init) void {
const gpa = init.gpa;
const io = init.io;
// Non-deterministic, OS-seeded PRNG
var rng_os = init.rng.seedOs();
// Deterministic, user-seeded PRNG
const seed: u64 = 123456789;
var rng_user = init.rng.seedUser(seed);
_ = gpa;
_ = io;
_ = rng_os;
_ = rng_user;
}
Proposed API surface (conceptual)
fn seedOs() std.Random.DefaultPrng
/// Returns a fast, non-cryptographic PRNG seeded from the operating system
/// (Unix / Windows). Intended for convenience and general use.
/// For reproducibility or custom RNGs, use std.Random directly.
fn seedUser(seed: u64) std.Random.DefaultPrng
/// Returns a fast, non-cryptographic PRNG seeded with the provided value.
Rationale
- RNG usage is extremely common in small tools and early experiments.
- This removes boilerplate without hiding policy: seeding is explicit.
- Returning a PRNG instance (not a shared stream) avoids hidden coupling.
- Advanced users can ignore this entirely and use
std.Randomas today.
Question
Would something like this be appropriate to include in std.process.Init, or does it conflict with Zig’s intent for Init as process plumbing?