I'm trying to write an extension for the Matrix example from the book, slightly tweaked to be generic.
I'm trying to write a method called getRow that returns a sequence of values at the given row.
In C#, I would have written this:
IEnumerable<T> GetRow (int row)
{
return Enumerable
.Range (0, this.columns)
.Select ((column) => this.grid[row, columns]);
}
or alternatively
IEnumerable<T> GetRow (int row)
{
for (var column = 0; column < this.columns; column++) {
yield return this.grid[row, column];
}
}
I'm not sure how to do this in Swift though.
Sequence seems to be the equivalent to IEnumerable<T> but I don't understand why it uses typealias instead of just being defined as Sequence<T> (see also this). Defining a method that returns generic Sequence<T> did not work:
extension Matrix {
// Cannot specialize non-generic type 'Sequence'
func getRow<T>(index: Int) -> Sequence<T> {
return map(0..self.columns, { self[index, $0] })
}
}
Then I got rid of <T> (but how is it supposed to be generic?):
extension Matrix {
func getRow(index: Int) -> Sequence {
return map(0..self.columns, { self[index, $0] })
}
}
This compiles! However I can't use it:
var row = grid.getRow(0)
// 'Sequence' does not conform to protocol '_Sequence_'
for i in row {
println("\(i)")
}
How do I properly type map result so it can be consumed in a for..in loop?
More on this issue: Associated Type Considered Weird
Joe Groff suggested to wrap the result in SequenceOf<T>:
extension Matrix {
func getRow(index: Int) -> SequenceOf<T> {
return SequenceOf(map(0..self.columns, { self[index, $0] }))
}
}
Indeed, this works but we had to wrap map result into a helper class which differs from how I do it in C#.
I have to admit I don't yet understand why Sequence and Generator use typealias and aren't generic protocols (like IEnumerable<T> in C#). There is an interesting ongoing discussion about this distinction so I'll leave a few links for a curious mind:
I think you are being mislead by the Swift compiler (which is a bit flaky at the moment). The type for your range 0..self.columns is Range<Int>, which is not a Sequence or Collection, so I don't think it can be used via map.
The implementation works for me:
extension Matrix {
func getRow(index: Int) -> T[] {
var row = T[]()
for col in 0..self.columns {
row.append(self[index, col])
}
return row
}
}
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