Home > OS >  Go generics with type constraints: cannot use false (untyped bool constant) as T value in assignment
Go generics with type constraints: cannot use false (untyped bool constant) as T value in assignment

Time:03-23

I have the following piece of code:

func createGrid[T int | bool](size int, forFlooded bool) [][]T {
    var tempGrid [][]T

    for i := 0; i <= size 1; i   {
        for j := 0; j <= size 1; j   {
            if forFlooded {
                tempGrid[i][j] = false
            } else {
                tempGrid[i][j] = -1
            }
        }
    }
    return tempGrid
}

I get the following errors on the lines where I'm assigning tempGrid[i][j]:

cannot use false (untyped bool constant) as T value in assignment
cannot use -1 (untyped int constant) as T value in assignment

This is how I'm using it:

var grid [][]int;
grid = createGrid(n, false);
var flooded [][]bool;
flooded = createGrid(n, true);

Here, I get CannotInferTypeArgs (cannot infer T) error.

I've also tried extracting that type constraint to an interface. What am I doing wrong?

Update:

Taking @kraylog's suggestions, I solved it using this:

func initialiseGrid[T int | bool](size int, fn func(i, j, size int) T) [][]T {
    var tempGrid [][]T

    for i := 0; i <= size 1; i   {
        for j := 0; j <= size 1; j   {
            tempGrid[i][j] = fn(i, j, size)
        }
    }
    return tempGrid
}
// In some function body:
grid := initialiseGrid(n, func(i, j, size int) int {
    if i == 0 || i == size 1 || j == 0 || j == size 1 {
        return -1
    } else {
        return int(math.Floor(rand.Float64() * 6))
    }
})
flooded := initialiseGrid(n, func(i, j, size int) bool { return false })

CodePudding user response:

Generics are a shortcut the compiler gives you for creating multiple instances of the same function, for different types.

Let's try to do the compiler's work manually. You'll get these two functions - one for int:

func createGridInt(size int, forFlooded bool) [][]int {
    var tempGrid [][]int

    for i := 0; i <= size 1; i   {
        for j := 0; j <= size 1; j   {
            if forFlooded {
                tempGrid[i][j] = false
            } else {
                tempGrid[i][j] = -1
            }
        }
    }
    return tempGrid
}

and one for bool:

func createGridBool(size int, forFlooded bool) [][]bool {
    var tempGrid [][]bool

    for i := 0; i <= size 1; i   {
        for j := 0; j <= size 1; j   {
            if forFlooded {
                tempGrid[i][j] = false
            } else {
                tempGrid[i][j] = -1
            }
        }
    }
    return tempGrid
}

Suddenly, this doesn't make sense anymore, since you can't assign false to int as in the first function, and the other way around in the second.

To solve the problem, you need to use T as the type you're working on. This also solves the code smell of passing a boolean flag to a function:

func createGrid[T int | bool](size int, fillWith T) [][]T {
    var tempGrid [][]T

    for i := 0; i <= size 1; i   {
        for j := 0; j <= size 1; j   {
            tempGrid[i][j] = fillWith
        }
    }
    return tempGrid
}

And you can call this with:

createGrid(n, false)
createGrid(n, -1)
  • Related