Creating multiple distinct types from a single type
The flipside of that principle is a situation in which we pass values of the same type, but which may have different meanings. A method may need to accept both inches and centimeters as Double, but will need to know which it is dealing with. We could add a second argument, a Bool that states whether or not the argument is in inches; but what about if there is also the need to accept millimeters? Or even lightyears?
This problem can also occur in compound data types; coordinates, for example, can be Cartesian or polar, but both would be expressed as a combination of two Double values.
Well, once again, there is a way. We can define an enum that consists of different cases wrapping the same type of data:
enum Coordinate
{
case cartesian(x: Double, y: Double)
case polar(r: Double, theta: Double)
}
So. we have created a type, Coordinate, which groups together two distinct cases that just happen to have the same associated value type.
Nevertheless, Coordinate.cartesian and Coordinate.polar are different types as far as the compiler's type-checking is concerned.
Let's see this in action:
let myCartesianPosition = Coordinate.cartesian(x: 100.0, y: 100.0)
let myPolarPosition = Coordinate.polar(r: 50.0, theta: 0.5)
var myCoordinates: [Coordinate] = []
myCoordinates.append(myCartesianPosition)
myCoordinates.append(myPolarPosition)
for coordinate in myCoordinates
{
switch coordinate
{
case .cartesian(let c):
// do something with Cartesian coordinate
print("Cartesian coordinate: x = \(c.x), y = \(c.y)")
case .polar(let p):
// do something with polar coordinate
print("Polar coordinate: r = \(p.r), theta = \(p.theta)")
}
}
This is a useful technique, and is worth experimenting with.