Reflection With the Lights On
I wanted a diagnostic printer for configuration structures and reached for reflection. That is normally the moment a small helper begins applying for framework status, so I kept the experiment deliberately narrow.
An interface value carries a dynamic type and value. The reflect package exposes descriptions of those two parts. In my weekly snapshot the entry points and names differ from examples written against other snapshots, so I will not pretend this code is timeless:
v := reflect.NewValue(x)
t := reflect.Typeof(x)
fmt.Println(t.String(), v.Kind())
From there I can switch on kind, inspect structure fields, and recursively print supported values. The mechanism is not source-code introspection. It is runtime examination of type information retained for a value.
The first rule I learned is to separate validity, kind, and concrete type. A pointer is not its element. An interface can contain a pointer. A nil interface and an interface containing a nil pointer are different states. Reflection faithfully presents these distinctions, even when I would prefer it to edit my mistake.
The second rule is that settable values are special. Inspecting a copy obtained from an interface does not grant permission to modify the original. To change a caller’s value, reflection needs an addressable value, usually reached through a pointer and then its element. This is good friction. Generic mutation should look dangerous because it is.
I ended with a read-only printer supporting strings, integers, slices, and exported structure fields. Unsupported kinds produce an explicit marker. I did not add automatic conversion, tag syntax, or clever cycle handling because the tool does not need them.
Reflection trades compiler knowledge for runtime decisions. Misspelled field assumptions become execution-path problems, and every branch is harder to read than direct code. It is justified when the types truly vary, as in encoders and diagnostics. It is not justified merely to avoid writing three straightforward assignments.
My opinion after using it is positive but cautious. Go’s reflection model follows the interface representation and type system rather than inventing a parallel object universe. Still, if ordinary interfaces can express the job, they are clearer and checked earlier. Reflection is a sharp tool. Keeping the lights on means seeing both the blade and the fingers.