Struct Embedding in Swift

Swift supports embedding of structs and protocols to express a more seamless composition of types. This is similar to inheritance but allows for more flexible composition.

import Foundation

struct Base {
    var num: Int
    
    func describe() -> String {
        return "base with num=\(num)"
    }
}

// A `Container` embeds a `Base`. In Swift, this is done through composition.
struct Container {
    var base: Base
    var str: String
}

// We can extend Container to provide direct access to Base properties and methods
extension Container {
    var num: Int {
        get { return base.num }
        set { base.num = newValue }
    }
    
    func describe() -> String {
        return base.describe()
    }
}

// Protocol similar to the `describer` interface in the original example
protocol Describer {
    func describe() -> String
}

// Make Base conform to Describer
extension Base: Describer {}

// Container automatically conforms to Describer due to the extension above
extension Container: Describer {}

func main() {
    // When creating structs with literals, we initialize the embedding explicitly
    let co = Container(base: Base(num: 1), str: "some name")
    
    // We can access the base's fields directly on `co`, e.g. `co.num`
    print("co={num: \(co.num), str: \(co.str)}")
    
    // Alternatively, we can spell out the full path using the embedded type name
    print("also num:", co.base.num)
    
    // We can invoke a method that was embedded from `Base` directly on `co`
    print("describe:", co.describe())
    
    // We can use Container as a Describer
    let d: Describer = co
    print("describer:", d.describe())
}

main()

To run the program, save it as StructEmbedding.swift and use the Swift compiler:

$ swift StructEmbedding.swift
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In this Swift version, we’ve used composition and protocol conformance to achieve similar functionality to struct embedding in Go. Swift doesn’t have a direct equivalent to Go’s struct embedding, but we can use composition and extensions to create a similar API.

The Container struct holds a Base instance, and we’ve added an extension to Container that provides direct access to Base properties and methods. This allows us to use co.num and co.describe() as if Base was embedded.

We’ve also defined a Describer protocol, similar to the describer interface in the original example. Both Base and Container conform to this protocol, allowing us to use them interchangeably where a Describer is expected.

This example demonstrates how Swift’s type system and protocols can be used to create flexible and composable types, similar to struct embedding in other languages.