Conformance
A type conforms to a protocol by stating it does, then providing the required members.
Stating conformance
The conformance goes on an extend block:
struct Point {
let x: Int
let y: Int
}
extend Point: Equatable {
public func isEqual(to other: Point) -> Bool {
self.x == other.x and self.y == other.y
}
}
Now any generic code constrained to Equatable accepts Point — and == works on Point values.
Multiple conformances
A type can conform to many protocols. Stack them in one extension or split across several:
protocol Drawable {
func draw()
}
struct Pixel {
let x: Int
let y: Int
}
extend Pixel: Equatable, Drawable {
public func isEqual(to other: Pixel) -> Bool {
self.x == other.x and self.y == other.y
}
public func draw() {
println("(\(self.x), \(self.y))");
}
}
Conformance via existing methods
If a type already has methods that match the protocol's signatures, the extension just states the conformance — you don't have to repeat the implementations:
protocol Countable {
func count() -> Int
}
struct Stack {
var items: [Int]
}
extend Stack {
public func count() -> Int { self.items.count }
}
extend Stack: Countable {} // Stack already has count()
The compiler matches existing members against the requirements automatically.
Conditional conformance
Sometimes a generic type only conforms when its type parameter does. Use a where clause:
struct Box[T] {
var value: T
}
extend Box[T]: Equatable where T: Equatable {
public func isEqual(to other: Box[T]) -> Bool {
self.value == other.value
}
}
Box[Int] is Equatable because Int is. Box[Connection] isn't, because Connection isn't.
Where to put the extension
Conformances can live in the same file as the type, in the same file as the protocol, or anywhere else — including a different module. This is the affordance that lets you make a foreign type conform to a protocol you control:
import std.collections.Array
protocol Summable {
func total() -> Int
}
extend Array[Int]: Summable {
public func total() -> Int {
var sum = 0;
for n in self { sum += n; }
sum
}
}
That's a powerful tool. Use it when the conformance genuinely belongs to your code; avoid it when it's something the upstream module should own.