Maybe I’m not imaginative enough, but I can’t think of a scenario where I’d implement an Error type that way. That said, this is interesting, thanks for sharing. I’m glad to hear that go vet catches this.
I think the code shown is a good example of the point being made, which is that programmers should understand how casting and implicit translation works in Go. Looking at it again, the recursion is way more obvious:
Typically, type A would be a struct of some kind, and not simply a string. Then, the Error() function would print some field of A, and not A in its entirety. In the case provided, however, the program attempts to Sprintf() the variable a; because a is not a primitive data type, there is an implicit translation to a.Error(), introducing the recursion
The typical scenario where you would implement MyError that way is more or less: type MyError uint32, where uint32 is an error code from some third-party API. You would expect the error message might want to include the uint32 value.
type MyError uint32
The title seems a little misleading: doesn’t the same thing happen if I make any type Foo implement the Stringer interface with the implementation calling itself?
It is a small foot-gun that is not reserved to errors.
The article suggests one detection method, i.e. reportedly go vet detects such situation. Therefore: do use go vet. Also, another good idea not mentioned in the article, would be: do write tests for your code. (You would then observe the stack overflow in a test, not in, say, production.)
Who says they’re not writing tests? The author merely encountered a confusing/surprising error message (possibly when writing a test) and wrote an article about it. go vet certainly gives more helpful guidance than fatal error: stack overflow:
fatal error: stack overflow
./a.go:14:9: Sprintf format %s with arg i causes recursive String method call
Hmm, yes, I think you’re right. Sorry for letting myself slip into something of a condescending tone. Thanks!
Not really related but we recently bumped into this at work and found it quite nasty: https://gist.github.com/yaaase/c3201392d00156cf5a2fd75a1f2b1162
(I have since read https://golang.org/doc/faq#nil_error but still think this is is a pretty crazy “gotcha”)
The dangers of structural typing! 😬