I don't really know what you mean by "optimization-defeating" here or in your other comment; unless the language offers some heavy duty compile-time partial-evaluation, there are fundamental costs to certain indirections. It's not just the result of the optimizer deciding not to inline or whatever, a dynamic jump costs more than a static jump.
I’m also not sure about the `benchmark{ ... }` syntax, but:
m := instance.Method; benchmark{ m() }
In the general case, this will require allocating a closure
and making a dynamic call.
m := type.Method; benchmark{ m(instance) }
This will require making a dynamic call.
benchmark{ instance.Method() }
This is a normal static call. It will be fast, even if not inlined. (Inlining today is often more critical as a supporting optimization for devirtualization than avoiding the minimal cost of a static call.)
---
reflect.ValueOf(it).Field(0).String()
`String()` is a bad case for a comparison here because it works and incurs a higher cost even if the field isn't a string.
60x sounds bad, but I really cannot stress enough: As soon as you're not doing a simple fixed-offset memory fetch from a base pointer, you might be paying 10x anyway no matter how good your optimizer is. That's just the cost of unpredictable memory access, even before we start talking about downstream impact on the code generator.
If you only want to support direct fields and not really the equivalent set of named fields you could type in a Go program, you can do some tricks with unsafe.Offsetof which will be faster, and probably cachable. But it's also called unsafe for a reason.