deep icon indicating copy to clipboard operation
deep copied to clipboard

Proposal: type specific hooks

Open dionysius opened this issue 1 year ago • 1 comments

I understand that it doesn't make sense to go in and try to support all possible core-ish types. E.g. like json.RawMessage as in #62.

Requesting an Equal method for the parent type may not be the best way to solve the culprit, a few caveats:

  • If that parent type was the one to be compared, there's no need anymore to use deep, one could just use the Equal method
  • If the type is used in hundreds of different parent types, there's a lot of Equal methods to write (a generator could be used/created)
  • The type in question as well the parent type(s) may not be in a package you control, so providing an Equal method is actually impossible

What I've seen in different other utilities is to offer a Hook for a type, which could be what is just missing. deep doesn't need to understand the type except to provide the framework for these hooks and this also allows to prototype a compare functions also for foreign types.

Examples:

deep already uses the package reflect, so there's no additional package needed.

Idea very rough from mind and may be incorrect. Good enough to show the idea:

import "reflect"

// signature of an equal func
type EqualFunc func(a, b reflect.Value) (bool, error)

// holds all the provided custom equal funcs
var customEqualFuncs map[reflect.Type]EqualFunc 

// add a custom equal func
func SetEqualFunc(t reflect.Type, f EqualFunc ) {
  customEqualFuncs[t] = f
}

// during equal() check whether a custom equal method exists
func equal(a, b interface{}) ... {
  ...
  // ^ has no Equal method, check if a custom equal func exists
  t := reflect.TypeOf(a)
  if f, exists := customEqualFuncs[t]; exists {
    isequal, err := f(reflect.ValueOf(a),reflect.ValueOf(b))
    ...
    return ...
  }
}

Would be used like:

deep.SetEqualFunc(reflect.TypeOf(json.RawMessage{}), func ... {
   ....
   return isequal, iserr
}

Missing above: diff return, which would need to be incorporated in the idea as well

Options to explore for EqualFunc:

  • type EqualFunc func(a, b interface) (bool, error) and use actual values instead of reflect.Value
  • using generics

Is such a hook a fitting candidate for deep in your opinion?

dionysius avatar Jun 23 '24 20:06 dionysius

Seems like a good idea because it wouldn't change the API but it would let users add functionality for bespoke data structures and comparisons.

daniel-nichter avatar May 02 '25 17:05 daniel-nichter