Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do Go generics fail when function returns a function?

I’ve just started trying out generics on Go, and I run into a situation which I don’t fully understand why it’s failing.

I’ve refactored the following function, from this:

func PositivePercentageAbove(above int) func(list []uint8) bool {
    return func(list []uint8) bool {
        acum := 0
        for _, x := range list {
            acum += int(x)
        }
        return (float64(acum) / float64(len(list)) * 100) >= float64(above)
    }
}

into this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

func PositivePercentageAbove[T constraints.Integer](above int) func(list []T) bool {
    return func(list []T) bool {
        acum := 0
        for _, x := range list {
            acum += int(x)
        }
        return (float64(acum) / float64(len(list)) * 100) >= float64(above)
    }
}

The unit test for this function is failing with error: tests/utils/NumberUtils_test.go:82:50: cannot infer T . The source is:

func Test_TruePercentageAbove(t *testing.T) {
    tables := []struct {
        percentage int
        list       []uint8
        output     bool
    }{
        {percentage: 100, list: []uint8{1, 1, 1, 1}, output: true},
        {percentage: 100, list: []uint8{1, 1, 0, 1}, output: false},
        {percentage: 80, list: []uint8{1, 1, 1, 1, 0}, output: true},
        {percentage: 90, list: []uint8{1, 1, 1, 1, 0}, output: false},
        {percentage: 100, list: []uint8{1, 1, 1, 1, 0}, output: false},
        {percentage: 40, list: []uint8{0, 1, 0, 1, 0, 1}, output: true},
        {percentage: 60, list: []uint8{0, 1, 0, 1, 0, 1}, output: false},
        {percentage: 70, list: []uint8{0, 1, 0, 1, 0, 1}, output: false},
    }

    for _, table := range tables {
        result := utils.PositivePercentageAbove(table.percentage)(table.list)

        if result != table.output {
            t.Errorf("Slice %v with percentage above %v expected to return %v but returned %v", table.list, table.percentage, table.output, result)
        }
    }
}

I’ve changed similar functions from int to generics, I’m not sure why this one in particular is not working. I assume it might be somehow related with the function returning another function, but I can’t figure exactly why. Thanks.

>Solution :

As often, the answer lies in the Type Parameters proposal:

The only type arguments that can be inferred are those that are used for the types of the function‘s (non-type) input parameters. If there are some type parameters that are used only for the function’s result parameter types, or only in the body of the function, then those type arguments cannot be inferred using function argument type inference.

In the case of

func PositivePercentageAbove[T constraints.Integer](above int) func(list []T) bool

because type parameter T does not appear in the parameter list, the corresponding type argument cannot be inferred.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading