On Wednesday, 17 July 2024 at 00:42:03 UTC, Walter Bright wrote:
> https://github.com/WalterBright/documents/blob/ed4f1b441e71b5ac5e23a54e7c93e68997981e9a/SafePrintf.md
Let’s say I have a @safe
-annotated function. If I understand the DIP draft correctly, it’s proposed that I can call printf
if
- the format is a compile-time constant (possibly derived through CTFE) and
plus the compiler:
- issues a hard error on incorrect use, e.g. number of arguments and specifiers mismatch,
- silently changes the format specifier if it’s meaningful, e.g.
%s
to %d
for integers, making %s
essentially universal,
- static array arguments are implicitly sliced, e.g. a
char[10]
argument becomes char[]
argument,
- if a
%s
specifier lines up with const(Char)[]
argument, silently changes the format specifier %s
to %.*s
/%.*ls
and the corresponding argument xs
is replaced by cast(int)(xs.length & int.max
and xs.ptr
.
My only issue is the & int.max
, that should be a non-assert feature. With asserts enabled, just assert(xs.length < int.max)
.
Otherwise, it’s a great idea. I’d make it __printf
, though, and ideally, __printf
becomes a new core-language keyword so that all the compiler-magic and special casing is appropriately justified. It should also not require any imports then, which would make it even easier to use. Changing printf
in any shape or form will make some people unhappy. I could imagine people being much happier having a keyword that is guaranteed to lower to a printf
call, with some checks and convenience added.
If we’re at it, __printf
could also support slices of non-character type: When a non-character array is an argument type that lines up with some specifier, cut the format in half, loop over elements and print them individually comma-separated and using that specifier, then continue with the rest of the format:
int a, b;
int[] xs;
int n = __printf("%d xyz %X abc %d", a, xs, b);
// lowers to:
int n = {
int __result = __printf("%d xyz [", a);
if (xs.length > 0)
{
__result += __printf("%X", xs[0]);
foreach (__x; xs[1..$]) __result += __printf(", %X", __x);
}
return __result + __printf("] abc %d", a, xs, b);
}();
A similar approach would work for associative arrays as well. What’s so cool about it is that it would work with nested arrays! The cutting-and-loop approach also works for struct
types, printing some header (the type name) and then the comma-separated tupleof
, provided the members are of printf-friendly types.