gogenericstype-parameter

Type Parameter Panicking in Function Call


I have a struct in Go, which represents a state. I now want to be able to compare two states (current & desired), whereby each field is compared with the other. I define two states as "equal" if all fields are "equal". However, in some cases, field equality is rather loose, which I want to be customely define.

Let's say one of the state fields in "RestartedAfter". If current-state RestartedAfter is greater than desired-state RestartedAfter, then I consider the two "equal".

In the example I only use a single field, but since I want to iterate over all fields of the struct (in the next step), I thought about using type parameters to define an AssertEqual() interface, which all fields in the state-struct should implement.

type StateField[T any] interface {
    AssertEqual(T) error
}

type RestartedAfter int

func (current RestartedAfter) AssertEqual(desired RestartedAfter) error {
    if current >= desired {
        return nil
    }
    return errors.New("current RestartedAfter happened before desired RestartedAfter")
}

func compareTwo[T any](x StateField[T], y T) error {
    return x.AssertEqual(y)  // panics
}

func main() {
    r1 := RestartedAfter(1)
    r2 := RestartedAfter(2)

    err := compareTwo[RestartedAfter](r1, r2)
    if err != nil {
        os.Exit(1)
    }
}

This example however panics. I get the following message: panic: interface conversion: main.StateField[go.shape.int_0] is main.RestartedAfter, not main.RestartedAfter (types from different scopes).

Any ideas of what's wrong?


Solution

  • I believe this is a bug described here: https://github.com/golang/go/issues/53376

    To fix in current version you can reassign the variables:

    func compareTwo[T any](x StateField[T], y T) error {
        a := x
        b := y
        return a.AssertEqual(b)
    }
    

    It works without the fix in latest dev branch: https://go.dev/play/p/KAPDHQW8RWH?v=gotip