I'm trying out some examples from the Swift book, namely the matrix example they have which introduces subscript options. This is the code I have:
struct Matrix<T> {
let rows: Int, columns: Int
var grid: T[]
var description: String {
return "\(grid)"
}
init(rows: Int, columns: Int, initialValue: T) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: initialValue)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> T {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
This is mostly copied from the book. A major difference is in this line here:
struct Matrix<T>
As far as I can tell, this says to the compiler that my Matrix class can hold values of type T, specified by the code using this class. Now, I'd like to make sure that the type T can be compared, so I can write this:
struct Matrix<T: Equatable>
This might be useful in case I want to compare 2 matrices, which would mean comparing their values. I also want to provide the ability to sum two matrices, so I should also add to this line a protocol requiring that the type 'T' given by the user of the matrix can be added:
struct Matrix<T: Equatable, "Summable">
Likewise, I'd also like to say:
struct Matrix<T: Equatable, "Summable", "Multipliable">
Question 1: What protocol name can I use? How can I achieve this?
On a related note, to add addition abilities using the '+' operator, I should declare a function like this (this applies also to multiplication):
@infix func + (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> {
// perform addition here and return a new matrix
return result
}
However, this code is not accepted by Xcode. More specifically, this ) -> Matrix<T> {
produces the error: Use of undeclared type 'T'
. What I mean by that <T>
is that the result will be a matrix that has the same type of the two input matrices, but I'm probably messing the syntax completely.
Question 2: How can I provide type information to the result of the addition?
Here's for your second question (but you really should ask two separate questions):
@infix func + <T> (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> { ... }
For your first question: before solving it, here's the syntax to define multiple constraints for type parameter:
struct Matrix<T where T: Equatable, T: Summable, T: Multipliable> {...}
or, as GoZoner writes in the comments:
struct Matrix<T: protocol<Equatable, Summable, Multipliable>> {...}
But we're not going to need it. First, define a new protocol and list the operations that you need. You can even make it extend Equatable
:
protocol SummableMultipliable: Equatable {
func +(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
}
Then, provide extensions for the types that you want to conform. Here, for Int
and Double
, the extensions are even empty, as the implementation of the needed ops is built-in:
extension Int: SummableMultipliable {}
extension Double: SummableMultipliable {}
Then, declare your type constraint on the type parameter:
struct Matrix<T: SummableMultipliable> { ... }
Finally, you can write stuff like this:
let intMat = Matrix<Int>(rows: 3, columns: 3, initialValue: 0)
let doubleMat = Matrix<Double>(rows: 3, columns: 3, initialValue: 0)
let i: Int = intMat[0,0]
let d: Double = doubleMat[0,0]
The last thing you'll need is to insert the type constraint in the definition of your operator:
@infix func + <T: SummableMultipliable> (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> { ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With