Extending Types
Two ways to shape types from outside their definition: extensions add behavior, type aliases name something that already exists.
Extensions
extend adds methods, computed variables, or protocol conformance to any type — including types you didn't define:
extend Array[Int] {
func sum() -> Int {
var total = 0;
for n in self { total = total + n; }
total
}
}
let total = [1, 2, 3].sum(); // 6
This works on stdlib types, your own types, and types from third-party modules. The extension lives in whatever file declares it; everywhere that file is imported, sum() is available on Array[Int].
You can also add conformance through an extension:
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
}
}
let same = Point(x: 1, y: 2) == Point(x: 1, y: 2); // true
Anywhere a function takes an Equatable, your Point now works.
If the protocol you're conforming to is generic, its type arguments can introduce free type parameters on the conformance line — no keyword-side declaration:
protocol Tagger[T] {
type Tagged
func tag(with value: T) -> Tagged
}
extend Int64: Tagger[T] {
type Tagged = (Int64, T)
public func tag(with value: T) -> (Int64, T) { (self, value) }
}
let pair = 3.tag(with: "bronze"); // (3, "bronze")
T is bound by the conformance, not by Int64. Reads as "for all T, Int64 conforms to Tagger[T]" — the stdlib uses the same shape to make Int64 index any Array[T].
For protocol-side extensions (adding behavior to all conformers of a protocol), see Protocols → Extending.
Type aliases
A type alias gives a new name to an existing type:
struct Request { let path: String }
struct Response { let status: Int }
public type UserId = Int
public type Handler = (Request) -> Response
public type StringDict[V] = Dictionary[String, V]
Aliases are not new types — they're just names. UserId is Int, with all the same methods and constraints. Don't reach for an alias when you want a distinct type with different rules; use a struct:
// distinct from Int — can't accidentally pass a row count where a UserId is expected
struct UserId {
let raw: Int
}
The two together are powerful: aliases for "this is a kind of Int we use a lot," structs for "this is a different thing that happens to be wrapped around an Int."