Skip to content

Modify elements during filter check to improve slice diffs #384

@bauersimon

Description

@bauersimon

Problem

Code (playground):

a := []int{1, 2}
b := []int{2, 3}
fmt.Println(cmp.Diff(a, b))

What happens:

[]int{
- 	1, 2,
+ 	2, 3,
  }

What I would like to see:

[]int{
  	2,
- 	1,
+ 	3,
  }

Solution

The workaround:

"Intercept" both slices before comparing and sort them such that matching items are at the front.

var dummy = cmp.Comparer(func(_, _ interface{}) bool { return false })

fmt.Println(cmp.Diff(a, b,
	cmp.FilterValues(func(x, y interface{}) bool {
		vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
		if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
			return false
		}
		if vx.Type() == reflect.TypeOf(([]int)(nil)) {
			xValue := vx.Interface().([]int)
			if xValue[0] == 1 {
				fmt.Println("found [1,2], (fake) sorting to have matching elements in the front (this would access the other slice in practice")
				xValue[0] = 2
				xValue[1] = 1
			}
		}
		return false
	}, dummy),
))

Is this correct/doable?

In the documentation it is often explicitly mentioned when a function must be pure (not modify). This is never mentioned for FilterValues. Does that mean that the workaround outlined above is okay?

Proper solution / proposal:

Can we have a Transformer that has access to both compared elements such as: func(T,T) R,R? Where we can do the sorting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions