I've resisted keeping a blog for a while. Writing takes time, and I'd usually rather be building something. But there are ideas that don't fit in a README, decisions that aren't obvious from the code, and things I've learned the hard way that might be worth preserving.
So here we are.
What this will be
Mostly technical writing. I work primarily in Rust — systems stuff, emulators, async services, the occasional game. I'm also studying discrete mathematics, so some posts will probably drift towards the mathematical end of things: algorithms, formal reasoning, the kind of structure that makes code provably correct rather than probably correct.
I won't post on a schedule. I'll write when I have something worth saying.
First thing worth saying
Fixed-point arithmetic is underused.
When I built the personal finance engine, the obvious choice was f64. It's what everyone uses for "numbers that need decimals." But f64 is binary floating-point — it cannot represent 0.1 exactly. Summing a thousand small transactions through f64 accumulates errors. That's a bad property for anything touching money.
The fix is fixed-point: represent every monetary value as an integer count of the smallest unit (pence, cents, whatever), and only format to a decimal string at display time. No rounding drift, no surprises.
// A monetary amount in pence. All arithmetic stays in integer space.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Money(i64);
impl Money {
pub fn from_pence(p: i64) -> Self { Self(p) }
pub fn from_pounds(pounds: i64, pence: i64) -> Self {
Self(pounds * 100 + pence)
}
}
impl std::fmt::Display for Money {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "£{}.{:02}", self.0 / 100, (self.0 % 100).abs())
}
}It's a small thing. But correctness-by-design beats correctness-by-luck.
More soon.