On Discord we've discussed and agreed to that it is currently too easy to accidentally pass an optional value (?T) to a format specifier like {s}. It is a real footgun and reminds me a lot to undefined that you can find on JavaScript websites in many places because the developer forgot to handle it. We don't want Zig to be like that. It shouldn't happily print null like that.
@InKryption had the idea of only allowing an optional type to be formatted if there is ? before the specifier type, so for {s} it would be {?s}.
Then @MasterQ32 asked about error unions and I proposed for example {!?s} to format anyerror!?[]const u8. I think this syntax looks really neat and it's consistent with the way the types look.
Here's what cipharius had to say:
That would be definitely more intuitive, as I previously also expected a type error, since in other contexts Zig is pretty strict about type inference.
So the proposal is to change std.fmt formatting such that in a format string
{t} can only format T,
{?t} can only format ?T (and T as that coerces to it),
{!?t} can only format anyerror!?T.
where t is the respective specifier type. This affects all specifier types except for any which will retain current behavior.
CC @InKryption @viriuwu @MasterQ32
On Discord we've discussed and agreed to that it is currently too easy to accidentally pass an optional value (
?T) to a format specifier like{s}. It is a real footgun and reminds me a lot toundefinedthat you can find on JavaScript websites in many places because the developer forgot to handle it. We don't want Zig to be like that. It shouldn't happily printnulllike that.@InKryption had the idea of only allowing an optional type to be formatted if there is
?before the specifier type, so for{s}it would be{?s}.Then @MasterQ32 asked about error unions and I proposed for example
{!?s}to formatanyerror!?[]const u8. I think this syntax looks really neat and it's consistent with the way the types look.Here's what cipharius had to say:
So the proposal is to change
std.fmtformatting such that in a format string{t}can only formatT,{?t}can only format?T(andTas that coerces to it),{!?t}can only formatanyerror!?T.where
tis the respective specifier type. This affects all specifier types except foranywhich will retain current behavior.CC @InKryption @viriuwu @MasterQ32