# Formatting strings

**URL:** <https://ziggit.dev/t/formatting-strings/6981>\
**Category:** Help\
**Tags:** language, standard-library\
**Created:** [November 23, 2024, 5:30pm UTC](https://ziggit.dev/t/formatting-strings/6981 "2024-11-23T17:30:09Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [November 23, 2024, 6:02pm UTC](https://ziggit.dev/t/formatting-strings/6981/2 "2024-11-23T18:02:37Z")

</div>

> [@Idiomatic Complex Formatting](https://ziggit.dev/t/idiomatic-complex-formatting/3735/5):
>
> The idiomatic way of implementing custom formatting would be to implement a format function. [std.fmt.format](https://ziglang.org/documentation/master/std/#std.fmt.format), which std.debug.print and other formatting functions that take a format string with placeholders are derived from, has this to say in its doc comment: If a formatted user type contains a function of the type pub fn format( value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void with ? being the type formatted, this function will be call…

* * *

> [@ericlang](#):
>
> I think this function is horribly wrong to return a local buffer isn’t it?

Yes, writing a format function is the easiest way to go and also the most flexible.

```zig
// as method of Square, see the link above if you want a freestanding function
pub fn format(
    self: Square,
    comptime _: []const u8,
    _: std.fmt.FormatOptions,
    writer: anytype,
) !void {
    const x: u8 = square_x(square);
    const y: u8 = square_y(square);
    try writer.print("{c}{d}", .{x + 'a', y + 1});
}

```

> [@ericlang](#):
>
> I also don’t want this function to fail. Should I write bufPrint catch unreachable?

In a context where I would rather use some default string then have to handle some error I use `std.fmt.allocPrint` (confusingly named because it formats, doesn’t print anything) like this:

```zig
var buffer: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();

const str = std.fmt.allocPrint(allocator, "{d}", .{id}) catch "<buffer too small>";
// do something with it
fba.reset();
// allocate something else ...

```

> [@ericlang](#):
>
> I also am not capable of reading functions in Zig which have `anytype` as an argument.  
> Like “writer”. how on earth can we discover what a “writer” is if it is anytype?

I think the only way is to read the documentation, or look how it is used in a ducktyping manner. For writer normally a [std.io.Writer](https://ziglang.org/documentation/master/std/#std.io.Writer) or [std.io.AnyWriter](https://ziglang.org/documentation/master/std/#std.io.AnyWriter) is expected or something that has these functions, but technically what ever works and has the functions that are used.

> [@ericlang](#):
>
> Should I write bufPrint catch unreachable?

You shouldn’t use bufPrint because you would return temporary memory.  
You shouldn’t use unreachable because of this [unreachable - error discarding misuse](https://ziggit.dev/docs?topic=3653#error-discarding-misuse-3) you could catch and return some default string, or catch and panic.

The returning a default string only works well if you use something like a FixedBufferAllocator or an arena, because with that you don’t have to free the allocations individually, which means using something like `catch "<buffer too small>"` won’t error because nobody will try to call free for that string literal.

---

_[View the full topic](https://ziggit.dev/t/formatting-strings/6981)._
