4

The program below prints "2.5"

package main

import (
    "fmt"
)

type myFloat64 float64

// func (f myFloat64) Error() string {
//     return fmt.Sprintf("Error with %v", f)
// }

func main() {
    var a myFloat64 = myFloat64(2.5)
    fmt.Printf("%v\n", a)
}

Interestingly, when I uncomment the Error() method, the program no longer prints "2.5"

Question: Why does adding an Error() method change program behavior? Pointers to the Go language specification explaining this behavior would be much appreciated.

7
  • 1
    This is how the fmt package is implemented. If the printed value implements error, its Error() method is called. Commented Dec 29, 2021 at 7:20
  • 1
    I started on an answer that would be at least partly redundant (hence the closed question) but look at this version on the Go playground. Note that I changed the fmt.Sprintf to use %f; if you leave %v in here and run this, you'll see the infinite recursion. Commented Dec 29, 2021 at 7:21
  • 1
    Because %v calls Error which again uses %v to format the value which calls Error whic hagain formats the value with %v which again calls Error .... You got a infinite loop which produces a SO. Commented Dec 29, 2021 at 7:21
  • 2
    I kinda think this question should be opened for other people asking the same question. The answer, OP, is because when you add the Error method to your float, you're creating an error type. You can see the spec here: go.dev/ref/spec#Errors Then, when you call Printf, the code calls that method during printing, defined here: cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/fmt/… Commented Dec 29, 2021 at 7:24
  • 2
    @Jorge, yes, your trick works, but the main problem is %v. This is a handy tool to format a thing you do not know what it is. But if you know what it is: Use an appropriate verb for your type. Commented Dec 29, 2021 at 7:40

1 Answer 1

5

myFloat64 implements the error interface:

type error interface {
  Error() string
}

fmt.Println() will consider a as an error value, and print the error message by calling a.Error(), which executes fmt.Sprintf("Error with %v", f). But Sprintf behaves just like Println, it also considers f as an error value and calls Error(). This recursion goes infinitely and causes stack overflow.

Sign up to request clarification or add additional context in comments.

1 Comment

Error interface defined here: go.dev/ref/spec#Errors

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.