Swift for Xojo Developers : Part 14 : 2D Array AND Pair Datatype

One of the shortcomings of Swift is the use of multi-dimensional arrays.
This can be done with Arrays of Arrays but you end up with a complex syntax

let x=a[x][y]

Here is a simple class the makes it more readable, and more like what one would expect

class Array2D<T> {
	let columns : Int
	let rows    : Int
	var array   : Array<T?>

	init(columns: Int, rows: Int,hasDefaultValue :T? = nil) {
		self.columns = columns
		self.rows = rows
		array = Array<T?>(repeating: hasDefaultValue, count: rows*columns)

	subscript(column: Int, row: Int) -> T? {
		get { return array[row*columns + column] }
		set { array[row*columns + column] = newValue }

to declare a array it would be something like this

var anArray   = Array2D<Int>(columns:3,rows:3,hasDefaultValue:9)
let x = anArray[2,2]

this creates a 3x3 array of Integers, with all values set to 9
behind the scenes it is in reality a 1 dimensional array
by using generics, the array can be of any datatype specified

Here is a simple class to use the PAIR datatype from Xojo … it uses GENERICS, something Swift has, but Xojo currently does not

Since the ‘:’ is a reserved symbol in Swift, the Swift Pair uses ‘<->’ instead

infix operator <-> : TernaryPrecedence
func <-><L:Any,R:Any>(lhs: L ,rhs: R)     -> pair<L,R> { return pair(left: lhs,right: rhs)}

class pair<L,R> {
	typealias Element = (L,R)
	private var value : Element?
	init(left:L,right:R) { value=(left,right) }
	public var left  : L { get { return value!.0 } }
	public var right : R { get { return value!.1 } }


func xyzz() {
	let p = pair(left: "A",right: 3)
	let p2 = 14.2 <-> "ABC"

:frowning: seems the PAIR works as long as you define them as in the example above…
but createing an Array where the pairs are not yet defined doesn’t work

var temp = [pair]

makes sense since the pair type is an incomplete type declaration

maybe the pair needs to know what types left & right are ?
not sure how you’d do that in swift - maybe like

    var temp = [pair<string, integer>]


yeah that does seem to be what is required… I was hoping to NOT have to do that

this make the pair “type safe”

variants are the source of so much grief

but it kind of defeats the purpose of generics if you have to predefine what they are…

Basically you cannot create and use a “generic” PAIR… since everytime you declare one, you need to tell it ahead of time what it is going to be

Ok… until I find a better solution… I’m just going to stick with String:String type pairs

infix operator <-> : TernaryPrecedence
func <->(lhs: String ,rhs: String)     -> pair { return pair(left: lhs,right: rhs)}
typealias  pair = (left: String,right: String)

generics are not chameleon types like Xojo’s variant
they are more like templates that you have to fully specify to use
many times they are a data type that has well defined operations on it but the actual data contained isnt important as long as it adheres to some API
For instance LIST has certain behaviours (can add to the beginning, remove, etc,) and the only time the data matters is if its a sortable list and then the data has to somehow adhere to a “comparable” interface
Beyond that the LIST type really doesnt care about if its a list of integers, strings, doubles, classes etc

the C++ STL is a great example of this principal
All the “types” it defines are really “algorithms” for how you implement certain data types without regard for what the data is

I hope this makes sense ?