Created
November 27, 2015 19:01
-
-
Save oisdk/048e9a986139e1cfca7e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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