Struct Embedding in F#

// F# supports composition of types through inheritance and interfaces.
// This example demonstrates a similar concept to Go's struct embedding.

open System

// Define a base record type
type Base = {
    Num: int
}

// Define a function for the base type
let describe (b: Base) =
    sprintf "base with num=%d" b.Num

// Define a container record type that includes Base
type Container = {
    Base: Base
    Str: string
}

// Define a discriminated union type for the interface
type Describer =
    | BaseDescriber of Base
    | ContainerDescriber of Container

let main() =
    // Create a Container instance
    let co = { 
        Base = { Num = 1 }
        Str = "some name" 
    }

    // Access the Base fields directly on Container
    printfn "co={num: %d, str: %s}" co.Base.Num co.Str

    // Alternatively, we can spell out the full path
    printfn "also num: %d" co.Base.Num

    // Call the describe function on the Base part of Container
    printfn "describe: %s" (describe co.Base)

    // Demonstrate polymorphism using the Describer type
    let d = ContainerDescriber co
    let describePolymorphic (describer: Describer) =
        match describer with
        | BaseDescriber b -> describe b
        | ContainerDescriber c -> describe c.Base

    printfn "describer: %s" (describePolymorphic d)

main()

This F# code demonstrates concepts similar to struct embedding in Go. Here’s an explanation of the key points:

  1. We define a Base record type with a Num field, similar to the base struct in Go.

  2. The describe function is defined separately, taking a Base as an argument, rather than being a method on the type.

  3. We create a Container record type that includes a Base field, mimicking the embedding in Go.

  4. The Describer discriminated union type is used to demonstrate polymorphism, similar to the describer interface in Go.

  5. In the main function, we create a Container instance and show how to access its fields.

  6. We demonstrate polymorphism using the Describer type and pattern matching.

To run this F# program:

$ dotnet fsi struct-embedding.fsx
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

This example shows how F# can achieve similar functionality to Go’s struct embedding through composition and discriminated unions. While the syntax and approach differ, the core concept of type composition is preserved.