A generic golang decorator (clarification needed for a gist)

Can someone explain what is happening in this gist ? I understand the concept of decorators and how this implementation lets one create a generic decorator, but I am little lost in a few sections (commented inline). Would really appreciate if someone could break it down for me. Also if this isnt the best way to write a generic decorator, what is ? I am looking for a decorator that can decorate a function of type func(args…interface{}) (interface{},error) without throwing away type safety.

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func Decorate(impl interface{}) interface{} {
  7. fn := reflect.ValueOf(impl)
  8. //What does inner do ? What is this codeblock ?
  9. inner := func(in []reflect.Value) []reflect.Value { //Why does this return the same type as the parameters passed to the function ? Does this mean this decorator only works for fns with signature func (arg TypeA) TypeA and not func (arg TypeA) TypeB ?
  10. f := reflect.ValueOf(impl)
  11. fmt.Println("Stuff before")
  12. // ...
  13. ret := f.Call(in) //What does call do ? Why cant we just use f(in) ?
  14. fmt.Println("Stuff after")
  15. // ...
  16. return ret
  17. }
  18. v := reflect.MakeFunc(fn.Type(), inner)
  19. return v.Interface()
  20. }
  21. var Add = Decorate(
  22. func (a, b int) int {
  23. return a + b
  24. },
  25. ).(func(a, b int) int) //Is this a type assertion ?
  26. func main() {
  27. fmt.Println(Add(1, 2))
  28. }

The variable inner is declared using a short variable declaration. The variable inner has type func(in []reflect.Value) []reflect.Value. The value is the function literal in the code.

The type func(in []reflect.Value) []reflect.Value represents a generic function implemented by reflection. The function takes a possibly empty slice of arguments and returns a possibly empty slice of results.

The reflect.Value for a function is not directly callable. The Call method is used to call the function in the value.

The .(func(a, b int) int) is a type assertion.

shareimprove this answer
answered Jul 30 ‘17 at 2:57

So this would require the type assertion everytime I want to use the decorator ? Seems a little clunky. Is there a way to do something by creating some kind of decorator for func(args…interface{}) (interface{},error) ? I am looking for a generic logging decorator not tied to a specific function signature. – nitimalh Jul 30 ‘17 at 3:01
@nitimalh You can create a function that accepts an arbitrary number of interface{} values, but can you do it for returning 1, 2, 10, etc. values, some also returning bool, error, int, etc.? The gist assumes a single value is returned, but multiple values may be returned by another function. This requires essentially the same code, except the return signature of the function will differ. There’s no way I’m aware of to fix this currently. That doesn’t mean it can’t be done of course. I just can’t conceive a viable implementation. – Chrono Kitsune Jul 30 ‘17 at 12:24
Yea I agree. That is the dilemma. I need to implement a generic logging decorator. Maybe there are some other patterns/tricks to acheive this ? – nitimalh Jul 30 ‘17 at 14:58
@nitimalh Code generation, as is the norm in Go for things like this? It’s like the preprocessor in C: you’re basically metaprogramming to create another part of your program. The Go equivalent of the C preprocessor is you, which is why many continue to argue for generics in Go 2. Perhaps if you can answer why you need such a function, you’ll get more useful responses sans generics. :( – Chrono Kitsune Jul 30 ‘17 at 15:19

ft_authoradmin  ft_create_time2018-04-28 14:34
 ft_update_time2018-04-28 14:35