Skip to content

New format string for std.fmt.format #8291

@JoaoSilveira

Description

@JoaoSilveira

There's a TL;DR go down there if you don't feel like reading all of this.

The problem

Some time ago I was writing a DateTime struct and stumbled upon a problem when writing the format method for it. My first idea was to use the [specifier] parameter to format the fields, and everything looked great until I needed to print a : (ISO8601 format) because you can't scape it in the [specifier]. There isn't (that I'm aware of) a solution for this other than to create a function to format the DateTime and print it's result.

The other thing I felt a bit bothered was the FormatOptions parameter. IMHO I think that the std.fmt.format function should be the responsible for the fill, alignment and width parameters, and precision is a floating point number only parameter (yes, you can find new uses for these in your format function, but you got the point).

Adding a condition to escape a : isn't that hard but I don't believe this is the way to go.

Proposal

I'd to propose the following format string {[argument][placement]:[specifier]}, where placement => '['[fill][alignment][width]']' (single quote meaning literal).

As I didn't find the issue that explains why any became obligatory in first place, any would maintain the status quo, although I personally don't find that it is necessary.

Pros

  • Remove unrelated parameters in the types' format. Ex: an error wouldn't get a precision parameter
  • Remove the necessity of putting argument inside brackets [] when referring to it by name, or when specifier starts with a number
  • The placement is inside brackets [], symbolizing the box where the value will fit (A really nice way of saying boilerplate)
  • The implementator of format don't need to worry about it's positioning
  • Remove the necessity of escaping :

Cons

  • This will break things, and broken things must be fixed
  • Every implementator of format will have to parse its own specifier (status quo, I guess)
  • This could be (and probably is) a really hard way to add an escape condition (I'm probably giving an edge case too much credit)

Examples

The first line is status quo, the second is the proposal.

// argument by index 
print("{0any}", .{ value });
print("{0:any}", .{ value });

// argument by name
print("{[arg]any}", .{ .arg = value });
print("{arg:any}", .{ .arg = value });

// with fill/align/width
print("{any:0<15}", .{ value });
print("{[0<15]:any}", .{ value });

// with index and fill/align/width
print("{0any:0<15}", .{ value });
print("{0[0<15]:any}", .{ value });

// floating point with precision
print("{e:.2}", .{ value });
print("{:e.2}", .{ value });

// when `specifier` starts with a number
print("{[0]555}", .{ value });
print("{:555}", .{ value });

// if we could escape `:` with \\, ISO8601 would look like this
print("{yyyy-MM-dd'T'HH\\:mm\\:ss.fffZ}", .{ value });
// the `specifier` is between the first `:` and `}`
// the only escape needed is for `}`
print("{:yyyy-MM-dd'T'HH:mm:ss.fffZ}", .{ value });

TL;DR

Change the current string format from (values inside '' are literals)

{[(index|'['name']')][specifier]:[fill][alignment][width].[precision]}

to

{[(index|name)]['['[fill][alignment][width]']']:[specifier]}

so we don't need to escape :, or to put argument inside brackets [] when referring to it by name or when its specifier starts with numbers

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingImplementing this issue could cause existing code to no longer compile or have different behavior.proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.standard libraryThis issue involves writing Zig code for the standard library.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions