Skip to content

proposal: fmt: improve ergonomics of fmt.Print-like functions #57816

Closed
@aarzilli

Description

@aarzilli

Proposals #57616, #50554 and #34174 all make a good argument for why functions in the fmt.Print family should be preferred to functions in the fmt.Printf family. However the fmt.Print family is rarely used in practice, so much that people even forget it exists 1 2.

The reasons for fmt.Print neglect are unknown but I propose that the reason is that the fmt.Print family does not have a few frequently used features that can only be accessed through fmt.Printf. I propose we add the following to the fmt package:

// Error formats a string like Sprint and returns it as a value that
// satisfies the error interface.
//
// If exactly one of the argument satisfies the error interface the returned
// error will implemnt an Unwrap method returning it. If there is more than
// one argument satisfying the error interface the Unwrap method will return
// a []error containing all of them.
func Error(a ...any) error

// Type returns the type of a.
func Type(a any) string

// ValueFormatter formats a value like the v verb of Printf
type ValueFormatter struct {
	...
}

// Value returns a ValueFormatter for a.
func Value(a any) *ValueFormatter

// Alt configures the ValueFormatter to print like #v.
func (*ValueFormatter) Alt() *ValueFormatter

// WithFields configures the ValueFormatter to add field names to the output.
func (*ValueFormatter) WithFields() *ValueFormatter

func (*ValueFormatter) String() string

Furthermore I propose that we change the documentation of Sprint to say the following:

Sprint formats using the default formats for its operands and returns the resulting string. Spaces are added between operands when neither is a string or a *ValueFormatter. 

Methodology

I downloaded the 10 most starred Go projects on github according to 3 excluding Go itself and awesome-go (which is a collection of links). I then used grep to find uses of Print and Printf like functions. I found the following uses:

Count Function
78055 Errorf
24355 Sprintf
2218 Println
1622 Printf
1528 Fprintf
1481 Sprint
1077 Debugf
323 Fprint
202 Print

I then parsed the first argument (when it was possible) and identified all formatting directives, including the character immediately following each of them. These were all the formatting directives used at least 100 times:

27305 "%v"
17161 "%d "
12069 "%s"
 8729 "%d"
 5895 "%s "
 4238 "%s:"
 3976 "%q"
 3673 "%v,"
 3401 "%v "
 3202 "%q "
 3170 "%w"
 2924 "%#v"
 1830 "%s,"
 1789 "%+v"
 1563 "%v:"
 1547 "%q:"
 1215 "%s'"
 1129 "%s/"
 1103 "%T"
 1093 "%d:"
 1043 "%q,"
  986 "%s\n"
  963 "%d,"
  944 "%v\n"
  643 "%s."
  607 "%#v,"
  560 "%s]"
  555 "%d]"
  517 "%v'"
  467 "%s-"
  465 "%T "
  369 "%t"
  359 "%d."
  319 "%v]"
  292 "%s%"
  288 "%#v\n"
  261 "%+v "
  249 "%s="
  237 "%+v,"
  233 "%v."
  223 "%#v "
  212 "%d/"
  182 "%x"
  182 "%v/"
  176 "%t,"
  175 "%q."
  165 "%d\n"
  164 "%q\n"
  162 "%d-"
  160 "%v;"
  153 "%#v:"
  143 "%s_"
  131 "%s\""
  119 "%+v\n"
  117 "%s}"
  108 "%s["
  106 "%s;"
  104 "%q]"

Cons

  • fmt.Printf has existed for a long time, it is possible that its use is too entrenched and this new API will never gain any traction. In that case this would add new API surface for no additional benefit.
  • fmt.Print is a worse interface for internationalization compared to fmt.Printf (so are all the string interpolation proposals). We may not want to encourage anything other than fmt.Printf, for this reason.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions