Apr 13, 2024 iOS

What enables SwiftUI’s DSL?

SwiftUI’s Domain-Specific Language (DSL) is enabled by several key language features and design decisions:

  1. Swift Language: SwiftUI is built using the Swift programming language, which provides powerful features such as closures, generics, function builders, property wrappers, and protocol extensions. These features enable SwiftUI to define its own declarative syntax for building user interfaces.
  2. Declarative Syntax: SwiftUI uses a declarative syntax, where you describe the desired user interface in terms of its state and behavior rather than imperatively specifying how to achieve it. This approach allows for concise and readable code, making it easier to understand and maintain UI code.
  3. View Composition: SwiftUI encourages composing complex user interfaces from smaller, reusable building blocks called views. Views can be combined and nested to create more complex layouts and UI elements. This composability is facilitated by Swift’s support for functional programming paradigms.
  4. Function Builders: SwiftUI uses function builders, a feature introduced in Swift 5.1, to transform a sequence of view-building expressions into a single composite view. Function builders enable SwiftUI to define custom syntax for constructing views, making the code more expressive and readable.
  5. Property Wrappers: SwiftUI employs property wrappers such as @State, @Binding, @ObservedObject, and @EnvironmentObject to manage the state of views and propagate changes through the UI hierarchy. Property wrappers provide a convenient way to encapsulate state and react to changes without boilerplate code.
  6. Modifiers: SwiftUI uses modifiers to modify the appearance and behavior of views. Modifiers are functions that transform views by applying various visual effects, layout adjustments, or behavioral changes. Modifiers allow for a fluent and concise way of expressing UI customization.
  7. Type Inference and Extensions: SwiftUI leverages Swift’s type inference capabilities and extension mechanisms to provide a clean and concise API for building user interfaces. Extensions allow SwiftUI to add custom functionality to existing types, making it easy to extend and customize the framework.

Overall, SwiftUI’s DSL is enabled by a combination of Swift language features, design patterns, and API conventions that promote simplicity, readability, and expressiveness in UI code.

if you look at the documentation for VStack‘s init(alignment:spacing:content:), you can see that the content: parameter has the attribute @ViewBuilder:

init(alignment: HorizontalAlignment = .center, spacing: Length? = nil,
     @ViewBuilder content: () -> Content)

This attribute refers to the ViewBuilder type, which if you look at the generated interface, looks like:

@_functionBuilder public struct ViewBuilder {

    /// Builds an empty view from an block containing no statements, `{ }`.
    public static func buildBlock() -> EmptyView

    /// Passes a single view written as a child view (e..g, `{ Text("Hello") }`)
    /// through unmodified.
    public static func buildBlock(_ content: Content) -> Content 
      where Content : View
}

The @_functionBuilder attribute is a part of an unofficial feature called “function builders“, which has been pitched on Swift evolution here, and implemented specially for the version of Swift that ships with Xcode 11, allowing it to be used in SwiftUI.

Marking a type @_functionBuilder allows it to be used as a custom attribute on various declarations such as functions, computed properties and, in this case, parameters of function type. Such annotated declarations use the function builder to transform blocks of code:

  • For annotated functions, the block of code that gets transformed is the implementation.
  • For annotated computed properties, the block of code that gets transformed is the getter.
  • For annotated parameters of function type, the block of code that gets transformed is any closure expression that is passed to it (if any).