Is this a thought experiment or is there a practical question here? If the latter, I’d like to get more information about the code/infrastructure around the code that lead to this situration.
I believe that one of the neat aspects of forums (and of this forum, in particular) is the follow-up questions that can maybe cause the asker (myself included) to reconsider their question in ways that the asker didn’t think of.
For example, instead of changing the function, f
, perhaps you could wrap it into another function, f′
, that checks and determines the function’s input and output types, like Yamil Bracho suggested. Your counter to that suggestion was that you’d have to change the function, but, in fact, you wouldn’t have to change the function if you wrapped the function – you’d have to change the code that calls the function (is it a requirement that the calling code not be changed as well?) – but not the function itself.
Also, is this an XY problem where you have determined that you need to know the input and output types of a function, but, perhaps, potentially, if you were to re-analyze the issue as a whole, it might be possible that the problem could be simpler than the way you see it at this time?
For example, perhaps the scenario is that you have some generic code where you register functions in some sort of repository like this:
func Register(name string, f func(interface{}) interface{}) {
someGlobalState.Store(name, f)
}
But (without having seen the architecture and/or usage of these func(interface{}) interface{}
functions), perhaps you could do this:
var someGlobalState sync.Map
type someGlobalStateKey struct {
TIn reflect.Type
TOut reflect.Type
}
func Register(name string, Tin, Tout reflect.Type, f func(interface{}) interface{}) {
key := someGlobalStateKey{TIn: Tin, TOut: Tout}
someGlobalState.Store(key, f)
}
// ... Some code that calls register later
func init() {
Register("sin", reflect.TypeOf(float32(0)), reflect.TypeOf(float32(0)), func (x interface{}) interface{} {
return float32(math.Sin(x.(float64)))
})
}
This way, you don’t have to do any runtime analysis of the function’s usage; it’s already registered with the proper types. You could add additional code around the usage of these functions (perhaps in debug builds) that check the types of the parameters and report errors for incorrect usage.
TL;DR
I think we need more information about the code/infrastructure around how these functions are declared and/or used to provide better answers.