Skip to content

Instantly share code, notes, and snippets.

@oisdk
Created November 27, 2015 19:01
Show Gist options
  • Save oisdk/048e9a986139e1cfca7e to your computer and use it in GitHub Desktop.
Save oisdk/048e9a986139e1cfca7e to your computer and use it in GitHub Desktop.
/// Conforming types should be able to perform standard Vector addition
protocol VectorAddable {
// The syntax is confusing here: the protocol requires that conforming types have
// a + function defined on them. However, since a.+(b) doesn't make much sense,
// we're defining it as a static function, with unnamed parameters. In practice,
// this works just the same as a method. The function + for vectors has the same
// scope as the types it's defined on.
static func +(_: Self, _: Self) -> Self
}
/// A concrete Vector type
struct Vector2D {
var x = 0.0, y = 0.0
}
// Extending the 2D vector type so that it gives a nice description
extension Vector2D: CustomStringConvertible {
var description: String {
return String((x,y))
}
}
// Extending the Vector2D type to conform to VectorAddable. To do this, you
// have to define a + function, but it's still only got the same scope as the
// Vector2D type itself.
extension Vector2D: VectorAddable {}
func +(lhs: Vector2D, rhs: Vector2D) -> Vector2D {
return Vector2D(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}
// Here's where protocols are poweful. Now, we can define a new method (scalarMultiply)
// and it will work on any vector types. We only have one now, but it's easy to define others.
extension VectorAddable {
func scalarMultiply(by: Int) -> Self {
var ret = self
for _ in 1..<by {
ret = ret + self
}
return ret
}
}
let myVec = Vector2D(x: 2, y: 1)
myVec.scalarMultiply(2) // (4.0, 2.0)
/// New Vector type
struct Vector3D {
var x = 0.0, y = 0.0, z = 0.0
}
extension Vector3D: CustomStringConvertible {
var description: String {
return String((x,y,z))
}
}
/// Extending it to conform to VectorAddable
extension Vector3D: VectorAddable {}
func +(lhs: Vector3D, rhs: Vector3D) -> Vector3D {
return Vector3D(x: lhs.x + rhs.x, y: lhs.y + rhs.y, z: lhs.z + rhs.z)
}
// Now we get scalar multiplication for free!
let my3DVec = Vector3D(x: 1, y: 2, z: 3)
my3DVec.scalarMultiply(4) // (4.0, 8.0, 12.0)
// We can even overload the * for scalar multiplication
func *<V:VectorAddable>(lhs: V, rhs: Int) -> V {
return lhs.scalarMultiply(rhs)
}
my3DVec * 4 // (4.0, 8.0, 12.0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment