The article gets close enough to this that I’m surprised they miss it: result types and typedefs get the best of both worlds. If you can define ResultString = Result<string> you don’t have to worry about the “fussy <>” problem (though I cannot tell if this was a serious critique or not), nor do you need to duplicate code you get from a non-generic implementation
In a language like OCaml this is really easy:
type UserIpResult = (UserIp, string) result
In Zig you can return error unions (either a value or an error) from functions. Values can be null unions (either a value or null).
For example !?u64 is a type that's either an error, a null or a 64-bit unsigned integer.