In Alan Donovan and Brian Kernighan's "The Go programming language" book p333 (section 12.3 Display, a recursive value printer), it is mentioned that
Where possible, you should avoid exposing reflection in the API of a package. We'll define an unexported function
display
to do the real work of the recursion, and exportDisplay
, a simple wrapper around it that accepts aninterface{}
parameter.
func Display(name string, x interface{}) {
fmt.Printf("Display %s (%T):
", name, x)
display(name, reflection.ValueOf(x))
And the display
function prints different contents depending on the Kind
of the input reflection value.
I have two questions
display
function considered as not exposing reflection in the API? Don't we still call reflection.ValueOf()
in Display
?I guess I don't know the definition of "exposing reflection in the package API". Does it just refer to the function arguments or both arguments and content? If it's the former case, then there seems no need to define display
since the signature of Display
is x interface{}
. If it's the latter case, why is it better?
In the book's example, it is because the usage of reflection is an implementation detail. You should always try to hide the implementation details, so you may change the implementation at any time without breaking the "public" API of the package. If you export / add something to the API of your package, you have to carry that for the rest of your life (given you don't want to make backward-incompatible API changes, which is really bad in general).
"interface{}
says nothing" – Rob Pike. Given that, reflect.Value
says even less. Unless you have a good reason (can't think of any outside of the reflect
package itself), you shouldn't create public functions that expect reflect.Value
as their arguments.
Even if you have a "general" function that must take a value of any type, interface{}
is preferred as then at least the clients can pass what they have as-is, without having to wrap them in reflect.Value
.