-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: fmt: add flags to control printing of slices #52936
Comments
This feature could be the basis for more flexibility in the formatting capabilities of my It currently supports several useful formats for a call frame:
But has only limited flexibility for slices of call frames:
|
What about a fmt.Sprintf("%v", fmt.ListFormatter(list, opts)) opts TBD but allow for custom separators and the like. Each item in the list uses the specified formatting directive. That probably wouldn't help with multierrors much but it would make it simpler to print prettier lists. It could be prototyped outside std using the regular formatter interface. Bringing it in to std would allow it to be lazy and reuse buffers. |
I don't doubt the need, but I am not sure we can redefine these characters to be flags instead of verbs. For example https://go.dev/play/p/nVDu4H-e5GX. It's true that on string it doesn't matter, but if we did fmt.Printf("%,v", customThing) and customThing had a Format method, then today Format gets called with verb = ','. Would it get called with verb = 'v' tomorrow? Or would the set of flags be different for things with Format methods and things without? |
This proposal has been added to the active column of the proposals project |
That is indeed unfortunate, as it appears to freeze the set of flags. It looks to me like we already (inadvertently?) made a breaking change to the set of verbs, though, with if verb == 'w' {
// It is invalid to use %w other than with Errorf, more than once,
// or with a non-error arg.
err, ok := p.arg.(error)
if !ok || !p.wrapErrs || p.wrappedErr != nil {
p.wrappedErr = nil
p.wrapErrs = false
p.badVerb(verb)
return true
}
p.wrappedErr = err
// If the arg is a Formatter, pass 'v' as the verb to it.
verb = 'v'
} It looks like previous uses of Maybe because it was so restricted in scope, but I don't recall seeing a single bit of fallout from that. All that said...
This seems like it would be the right choice (sadly). We would then document the exact set of flags compatible with |
This proposal looks sensible to me for basic types. Perhaps a different proposal but how would it print slices of complex structs? |
I threw together a quick proof of concept for using a generic |
I am still not sure about changing the flag semantics, nor about exactly where the line is for where we stop putting features into format strings. (Perhaps we've already crossed it.) /cc @robpike |
Fmt can't do everything. Other packages can, though. |
I've added (perhaps too many) knobs to my proof of concept and published it for anyone who needs it: https://pkg.go.dev/github.com/jimmyfrasche/slicefmt |
It sounds like maybe we've converged on not changing the standard library and instead focusing on other packages to provide this kind of thing. Do I have that right? |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
TL;DR
Proposal
Pretty-printing a slice of things is a common task. Yet it takes a fair amount of code to convert
[]int{1, 2, 3, 4}
into a pretty"1, 2, 3, 4"
. (Either print into a buffer, checking indices to avoid a trailing comma, or convert into strings and use strings.Join.)This is the sort of common task that fmt could make easy, for a few common separators: comma, semicolon, and newline.
I propose that we add corresponding flags to control how package fmt prints slices.
Though this proposal only deals with slices, it was motivated by thinking about the question about how a multierr in the standard library would format (#52607 (comment), #47811 (comment)). This fmt flag would extend naturally to common formatting choices for multierrs. (And potentially to maps and structs, but that's less obvious to me.)
Q&A
Alternatives
The primary alternatives here are:
The drawbacks to those are:
Using fmt.Formatter would help with doing work lazily and with not allocating into a separate buffer. However, fmt.Formatter is not easy to hold. (Related: #51668.) And there are no generic methods, so there's no way to do this in a generic way. In particular, this requires extra hoops for the most common slice types, like
[]int
and[]string
(and interface-based multierrs?), which is where I would anticipate this being used the most.Downsides
Package fmt is already complicated. This further increases that complication.
Tools that parse and interpret fmt formatting strings might require updating.
cc @robpike @jba @neild @ianlancetaylor @maja42 @jimmyfrasche @rogpeppe
The text was updated successfully, but these errors were encountered: