go: fmt: surprising behavior of structs with embedded error

Reported at the request of @FiloSottile after talking to him about it at #gopherconIS.

What version of Go are you using (go version)?

1.10.2 windows/amd64

Does this issue reproduce with the latest release?

I do not know, but i assume so since this is a syntax/behavior that i assume has not been changed.

What operating system and processor architecture are you using (go env)?

Windows amd64 gopath is set to my configured one, everything else is default

What did you do?

https://play.golang.org/p/0BPsgof_9oI

https://play.golang.org/p/Z3hV6sMz9Ko (as minimal as it can be i think)

What did you expect to see?

I expected my stringer to be called and a string get generated

What did you see instead?

%!v(PANIC=runtime error: invalid memory address or nil pointer dereference)

Extra

Now, i was at a lecture at #gopherconIS while coding this and listening. So my full focus was not on debugging this, which is probably the reason it took me hours to figure out.

I was even using GoLand to debug it, but my breakpoints were useless at the time because my program was going from a fmt.Println(... directly to the Panic! thing… (also the debugger took forever to start, sometimes even giving me a connection refused error, but that’s a different problem)

Now i assume most of you noticed my mistake, i did solve the problem eventually, i forgot to name the variables in my struct.

But the problem is that i did not understand why it is so important to name them until i met up with @FiloSottile at #gopherconIS. He explained to me that when i add these “naked” types to a struct, their functions actually join my struct (WTF???), in this case, Error() was suddenly a member of it, satisfying the only thing that Error interfaces need…

Solution

I don’t know how to solve this, i assume “naked” types in structs are a desirable quality for something, but being a beginner at Go i have not been exposed to them.

You also don’t do warnings, which is cool, maybe a linter can spot it?

But how many false positives would that have?

Maybe printArg() in $GOROOT/fmt/print.go could add a case in the default inside the giant switch, to not panic?

Or panic with a more descriptive error? (You fit the Error interface but that function is derpy, go fix your struct)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (13 by maintainers)

Most upvoted comments

Regardless of the final form of a potential new message in the event of a panic: Is more information in the panic string to make behavior with embedded methods more explicit worth breaking existing GO1 compatibility and possible programs that may depend on the documented syntax of %!verb(PANIC=panicstring)?

AFAIK in the past changes to fmt have been avoided to not break existing behavior (uint8 vs byte, length of %#06x vs %#6x …).