Need help for generics and extension

I have defined a struct for 2D Arrays :


struct Array2D<T: Equatable> {
    var matrix : [[T]]
    private var nRows, nCol : Int

// .......

I have defined an extension for ==


extension Array2D : Equatable { }
func ==<T>(x: Array2D<T>, y: Array2D<T>) -> Bool { /
    if (x.nRows != y.nRows) || (x.nCol != y.nCol) { return false }
    for i in 0..<x.nRows {
        for j in 0..<x.nCol {
            if (x.matrix[i][j] != y.matrix[i][j]) { return false }
        }
    }
    return true
}


I want now to define a ~operator, that will work only for Bool (T : Bool) ; something like:


prefix func ~<T>(x: Array2D<T>) -> Array2D<T> {
    var y = x   /
    for i in 0..<x.nRows {
        for j in 0..<x.nCol {
            y.matrix[i][j] =  !x.matrix[i][j]
        }
    }
    return y
}


Of course, this should be limited to T : Bool ; how can I insert a "where T == Bool" clause in the operator definition ?

Answered by guywithmazda in 139863022

I think you would just do this, which as jeschot mentioned is not generic; there's no reason it would need to be.

prefix func ~(x: Array2D<Bool>) -> Array2D<Bool> {
    var y = x
    for i in 0..<x.nRows {
        for j in 0..<x.nCol {
            y.matrix[i][j] = !x.matrix[i][j]
            print(i, j)
        }
    }
    return y
}

BTW, you probably need to make sure you have code in your struct to make sure nRows and nCol match the actual size of matrix. You may already be doing this, but since you didn't post your whole structure it's not obvious, so I thought I'd mention it. You could make them read-only computed properties that return the appropriate array's count property.

I don't think this makes sense.

If you constrain T to a specific type the function is no longer generic (that is actually the compiler message you get).

Type constraints require a type to conform to a protocol or derive from some class.

Equalities may occur in complex constraints but they involve generic types, not concrete types.

Accepted Answer

I think you would just do this, which as jeschot mentioned is not generic; there's no reason it would need to be.

prefix func ~(x: Array2D<Bool>) -> Array2D<Bool> {
    var y = x
    for i in 0..<x.nRows {
        for j in 0..<x.nCol {
            y.matrix[i][j] = !x.matrix[i][j]
            print(i, j)
        }
    }
    return y
}

BTW, you probably need to make sure you have code in your struct to make sure nRows and nCol match the actual size of matrix. You may already be doing this, but since you didn't post your whole structure it's not obvious, so I thought I'd mention it. You could make them read-only computed properties that return the appropriate array's count property.

Thanks for the advices.


In the Array2D, I effectively test the size :


extension Array2D : Equatable { }
func ==<T>(x: Array2D<T>, y: Array2D<T>) -> Bool { /
    if (x.nRows != y.nRows) || (x.nCol != y.nCol) { return false }
    for i in 0..<x.nRows {
        for j in 0..<x.nCol {
            if (x.matrix[i][j] != y.matrix[i][j]) { return false }
        }
    }
    return true
}


Here is the full struct:


struct Array2D<T: Equatable> {
    var matrix : [[T]]
    private var nRows, nCol : Int

    init(nbRows: Int, nbCol: Int, repeatedValue: T) {
        nRows = nbRows
        nCol = nbCol
        var tab = Array<Array<T>>()
        for _ in 0..<nbRows {
            tab.append(Array(count:nbCol, repeatedValue: repeatedValue))
        }
        matrix = tab
    }
  
    func row(rowIndex: Int) -> Array<T> {
        return self.matrix[rowIndex]
    }
  
    func column(colIndex: Int) -> Array<T> {
        var aCol = [T]()
        for i in 0..<nRows {
            aCol.append(self.matrix[i][colIndex])
        }
        return aCol
    }
  
    func colCount() -> Int {
        return self.nCol
    }
  
    func rowCount() -> Int {
        return self.nRows
    }
  // Some functions for debug
    func print() {
        for i in 0..<nRows {
            for j in 0..<nCol {
                Swift.print(self.matrix[i][j])
            }
        }
    }
    func printByRow(aRow: Int) {
        Swift.print(self.matrix[aRow])
    }

In the ~func, I do not need, as y is computed from x.

What I mean is that, if you have other code in the same file as your struct definition, you could do something like this:

var a2 = Array2D(nbRows: 1, nbCol: 1, repeatedValue: true)
a2.nCol = 5
a2.nRows = 5

Because the private keyword only restricts access from code in other source files. Now, the nCol and nRows properties and the colCount and rowCount functions do not indicate the actual size of the array, and the row and column functions will crash.

If you have the struct definition in it's own source file with nothing else, it won't be a problem.

As I mentioned, to make sure even code in the same source file can't mess things up, you could use read-only computed properties and get rid of the colCount and rowCount functions.

struct Array2D<T: Equatable> {
    var matrix : [[T]]
    var nRows: Int {
        return self.matrix.count
    }
    var nCol : Int {
        if self.matrix.count > 0 {
            return self.matrix[0].count
        } else {
            return 0
        }
    }
 

Also, your row and column functions should check to make sure that the index value passed in is not larger than nRows-1 (for row) or nCol-1 (for column).

Need help for generics and extension
 
 
Q