How to deal with giant structs?

Hi,

I'm trying to implement SwiftGen in combination with Swift-Dependencies (TCA Dependency Injection). I got SwiftGen to generate a Client with more than 1400 let variables and some closures example:

public struct TranslationClient: Sendable {
     public let home: String
     public var amountOfBooks: @Sendable(Int) -> String = { _, in "translation not found!")

    /// around 1400 more of these kinds of variables
}

When I compile the package this Client is in, I get an error:
/Localize.swift Command SwiftCompile failed with a nonzero exit code

If I check what the error actually is it just mentions a stack dump and to report it...

Is there a good way to handle these giant structs or is this just a limit of the compiler?

If you (manually) split it into a struct with ~40 fields which are in turn structs of ~40 vars, changing the rest of the code appropriately to account for this change, will it speed things up? If yes – that's the way SwiftGen to consider.

1 Like

And then generate @dynamicMemberLookup conformances for all of the inner types, you could even keep the API on the client completely flat.

2 Likes

Can you give me a simple example on how to achieve this with @DynamicMemeberLookup? I can generate different structs based on the Localization Table names so that's not really an issue. But I don't see how this is going to work with Swift-Dependencies?

You can flatten property access through @dynamicMemberLookup. If you have a nested type, you can flatten it into the parent.

@dynamicMemberLookup
struct Parent {
  struct Child {}

  private let child: Child

  subscript<T>(dynamicMember dynamicMember: KeyPath<Child, T>) -> T {
    child[keyPath: dynamicMember]
  }
}

Then implement another subscript for each child type.

1 Like

Do you need instance properties or static let properties are possible?

public struct TranslationClient: Sendable {
     public static let home: String
     public static var amountOfBooks: @Sendable(Int) -> String = { _, in "translation not found!")
    // ...
}

@Dmitriy_Ignatyev

I'm using Swift-Dependencies client mechanism so I don't know if that'll work with static let properties. (Keep in mind the TranslationDelegate is something from our codebase)
How it should work according to documentation:

import Dependencies
import DependenciesMacros
import Foundation

@DependencyClient
public struct TranslationClient: Sendable {
    public let tabbarBooking: String
    public let tabbarHome: String
    public var amountOfBooks: @Sendable (Int) -> String = { _ in "Translation not found" }
}

extension TranslationClient: TestDependencyKey {
    public static var testValue = Self(
        tabbarBooking: "Bookings",
        tabbarHome: "Home",
        amountOfBooks: { p1 in
            "Amount of books: \(p1)"
        }
    )
}

public extension DependencyValues {
    var translationClient: TranslationClient {
        get { self[TranslationClient.self] }
        set { self[TranslationClient.self] = newValue }
    }
}
import Dependencies
import Foundation

public protocol TranslationDelegate: AnyObject, Sendable {
    func translate(key: String, args: CVarArg...) -> String
}

public extension TranslationClient {
    static func live(translationDelegate: TranslationDelegate) -> Self {
        Self(
            tabbarBooking: translationDelegate.translate(key: "tabbar_mmb"),
            tabbarHome: translationDelegate.translate(key: "tabbar_home"),
            amountOfBooks: { p1 in
                translationDelegate.translate(key: "amount_of_books", args: p1)
                
            }
        )
    }
}

I'm now trying to split everything up into more structs so the compiler doesn't crash with SwiftGen and use @dynamicLookup to see if that works