Skip to content

Extensions ​

Implementation status: extension methods / protocol conformance / computed properties (Phase 136 GA) / constrained extensions Implemented (Phase 40–42); nested types inside an extension Partially implemented; cross-module extension Implemented (Phase 60 module-local witness)

An extension adds capability (methods, computed properties, protocol conformances, initializers) to an existing type without modifying the original declaration. SYX follows the Swift style; multi-constraint where clauses have been supported since Phase 42.

extension Methods ​

swift
extension Int {
    func doubled() -> Int { return self + self }
    func times(_ f: () -> Void) {
        for _ in 0..<self { f() }
    }
}

func main() {
    print(3.doubled())                    // 6
    3.times({ print("hi") })              // "hi" × 3
}

self inside an extension refers to the instance of the extended type (same as inside a class method).

Source: crates/syx-driver/tests/fixtures/types/greeter_extension.sy

extension Computed Properties ​

Phase 136 GA (lang-props-v4:extension-computed-mvp):

swift
extension Int {
    var isEven: Bool { get { return self % 2 == 0 } }
    var squared: Int {
        get { return self * self }
        set { /* illustration only; may reset a stored field */ }
    }
}

print(4.isEven)                          // true
print(3.squared)                         // 9
FormStatus
get-onlyImplemented (Phase 134)
get / setImplemented (Phase 135)
Cross-moduleImplemented (Phase 60 module-local)

Protocol Conformance ​

swift
protocol Named {
    var name: String { get }
}

extension User: Named {
    var name: String { return "User(\(self.id))" }
}

class User {
    let id: Int
    init(id: Int) { self.id = id }
}

Binding order does not matter: an extension may be written before the class declaration; the compiler later scans all extensions and synthesizes witnesses.

Protocol Default Implementations ​

swift
protocol Greetable {
    func greet() -> String
}

extension Greetable {
    func greet() -> String { return "Hello" }    // Default
}

class User: Greetable {
    // Inherits the default → "Hello"
}

class Loud: Greetable {
    func greet() -> String { return "HI!" }      // Override
}

Constrained Extensions (where) ​

swift
extension Array where Element: Equatable {
    func unique() -> Array<Element> {
        var seen: Array<Element> = []
        for item in self {
            if (!seen.contains(item)) {
                seen.append(item)
            }
        }
        return seen
    }
}

let nums = [1, 2, 2, 3, 3, 3]
print(nums.unique())                      // [1, 2, 3]

Multiple Constraints ​

Supported since Phase 42:

swift
extension Array where Element: Equatable, Element: Hashable {
    func toSet() -> Set<Element> {
        var s: Set<Element> = []
        for item in self { s.insert(item) }
        return s
    }
}

Constraint not satisfied: compile error S010. Tests: fixtures/format/extension_where_mvp / fixtures/format/extension_where_mvp / fixtures/format/extension_where_mvp.

extension Initializers ​

swift
struct Point {
    var x: Int
    var y: Int
}

extension Point {
    init() {                              // Convenience init
        self.init(x: 0, y: 0)
    }
}

let p = Point()                            // (0, 0)

Limit: an init inside an extension must delegate to a designated init of the original type; it cannot define new stored fields.

Cross-Module extension ​

An extension in module A may extend a type from module B:

swift
// In module A
extension String {
    func swaCount() -> Int { return self.count }
}

Current implementation: cross-module extensions have been fully supported since Phase 60; integrated with module-local witnesses. Swift's same-module restriction is relaxed (note: this is SYX behavior; Swift does not allow cross-module extensions).

Adding Methods to Basic Types ​

swift
extension Int {
    func clamp(_ lo: Int, _ hi: Int) -> Int {
        if (self < lo) { return lo }
        if (self > hi) { return hi }
        return self
    }
}

let x = 100.clamp(0, 10)                  // 10

extension and Access Control ​

swift
public extension Int {
    public func toHex() -> String { return "" }   // Must be annotated explicitly
}

Current status: public / internal annotations on extensions and members are Implemented (S005 cross-module checking).

extension and KeyPath ​

swift
extension User {
    var nameKp: KeyPath<User, String> { return \User.name }
}

Status: KeyPath is usable inside extensions (Partially implemented).

Complete Example ​

swift
protocol Describable {
    func description() -> String
}

@Equatable
data class User(id: Int, name: String)

extension User: Describable {
    func description() -> String { return "User(\(id): \(name))" }
}

extension Array where Element: User {
    func findByName(_ n: String) -> User? {
        for u in self {
            if (u.name == n) { return u }
        }
        return nil
    }
}

extension Int {
    var isEven: Bool { return self % 2 == 0 }
    var isOdd: Bool  { return !self.isEven }
    func clamp(_ lo: Int, _ hi: Int) -> Int {
        if (self < lo) { return lo }
        if (self > hi) { return hi }
        return self
    }
}

func main() {
    let users = [User(id: 1, name: "Alice"), User(id: 2, name: "Bob")]
    print(users.findByName("Bob")?.description() ?? "n/a")

    let n = 42
    print(n.isEven, n.clamp(0, 10))         // false 10
}

Diagnostics ​

CodeTriggerFix
S001An extension method conflicts with an existing oneRename it
S010where constraint not satisfiedCheck protocol conformance
S005An extension accessing an internal symbol across modulesChange it to public

Differences from Swift ​

SwiftSYX
extension methods / propertiesImplemented
extension protocol conformanceImplemented
Cross-module extensionImplemented (Phase 60; Swift does not allow it)
extension where with multiple constraintsImplemented (Phase 42)
init inside an extensionImplemented (delegating to a designated init)
Nested types inside an extensionPartially implemented
subscript inside an extensionPartially implemented
Stored fields inside an extensionNot implemented (only init / computed properties)
Retroactive conformance warningNot implemented (SYX allows cross-module extensions)

Next chapter → Protocols

See also → Language Reference: Declarations · Language Reference: Protocols and Conformances · Chapter 11, Properties · Chapter 23, Protocols

SYX · Apache-2.0