Inside SwiftUI’s Declarative Syntax’s Compiler Magic

defaultValue } set { UserDefaults.


set(newValue, forKey: key) } }}I can now use isFirstBoot as follows:@UserDefault(key: "isFirstBoot", defaultValue: false) var isFirstBoot: BoolThis allows you to interface with the complex generic type, but visually see nothing but a regular Bool property, As stated, the attribute empowers compiler magic to abstract the creation of the original generic type.

Because the full implementation of it deserves an How 'x' Works Internally in Swift article of its own, we'll jump to the interesting parts — with property delegates, the compiler translates the previous declaration to this:var $isFirstBoot: UserDefaults<Bool> = UserDefaults<Bool>(key: "isFirstBoot", defaultValue: false)var isFirstBoot: Bool { get { return $isFirstBoot.

value } set { $isFirstBoot.

value = newValue }}The use of $ as a prefix is on purpose; Even though isFirstBoot is a Bool, I might still want to access properties and methods from the more complex generic type.

Although the original property is hidden, you can still access it for this purpose.

For example, here's an example where UserDefault has a method for returning it to the default value:extension UserDefault { func reset() { value = defaultValue }}Although Bool won't have this property, I can use it from $isFirstBoot:$isFirstBoot.

reset()This is why Toggle(isOn: $showFavoritesOnly) in SwiftUI's example use $: it doesn't want the actual Bool, but the Binding property provided by the State property delegate struct which will be able to trigger a view reload when it changes.

/// A linked View property that instantiates a persistent state/// value of type `Value`, allowing the view to read and update its/// value.

@available(iOS 13.

0, OSX 10.

15, tvOS 13.

0, watchOS 6.

0, *)@propertyDelegate public struct State<Value> : DynamicViewProperty, BindingConvertible { /// Initialize with the provided initial value.

public init(initialValue value: Value) /// The current state value.

public var value: Value { get nonmutating set } /// Returns a binding referencing the state value.

public var binding: Binding<Value> { get } /// Produces the binding referencing this state value public var delegateValue: Binding<Value> { get } /// Produces the binding referencing this state value /// TODO: old name for storageValue, to be removed public var storageValue: Binding<Value> { get }}Function BuildersWe’ve seen how single expression don’t need to add return statements, but what the hell is going on here?HStack { Text("Hi") Text("Swift") Text("Rocks")}This will result in a nice horizontal stack with three labels, but all we did was instantiate them!.How could they be added to the view?The answer to this is perhaps the most groundbreaking change in SwiftUI — function builders.

The function builders feature pitch was introduced to the Swift community right after SwiftUI was released, allowing Swift to abstract factory patterns into a clean visual declarative expression.

All indicates that it’ll be part of Swift itself very soon, but for now you can try it as part of SwiftUI.

Function builders relate to types that, given a closure, can retrieve a sequence of statements and abstract the creation of something more concrete based on them.

HStack can do this because it has the ViewBuilder function builder in its signature:public init(.

, content: @ViewBuilder () -> Content)//Note: The official docs won't show the attribute, and I'm not sure why,//but you can confirm it has it by adding a normal expression `let a = 1` expression inside of the closure.

//It will give you a compilation error.

@ViewBuilder translates to the ViewBuilder struct: a function builder that can transform view expressions into actual views.

Function builders are determined by the @_functionBuilderattribute (with an underline because we're not supposed to use it manually yet) and a series of methods that determine how expressions should be parsed:@_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 // Not here: Another 9 buildBlock methods with increasing amount of generic parameters}We don’t really know what’s going on inside these methods as they are internal to SwiftUI, but we know the compiler magic behind it.

That example will result in the following:HStack { return ViewBuilder.

buildBlock(Text("Hi"), Text("Swift"), Text("Rocks"))}The more complex the block, the more complex the magic’d expression is.

The important thing here is that function builders block can only contain content that is understandable by the builder.

For example, you can only add an if statement to HStack because it contains the related buildIf()method from the attribute.

If you want an example of something that doesn't work, try the following:HStack { let a = 1 //Closure containing a declaration cannot be used with function builder 'ViewBuilder' Text("a")}The purpose of this feature is to enable the creation of embedded DSLs in Swift — allowing you to define content that gets translated to something else down the line, but it plays a big role in giving the declarative programming feeling to Swift.

Here’s how building a HTML page can look with this function builders:div { p { "Call me Ishmael.

Some years ago" } p { "There is now your insular city" }}The version of the feature inside Xcode 11 is internal and has less features than the proposed Swift version, and thus shouldn’t be used manually until it's officially added into the language.

ConclusionSwiftUI has just been announced and it’s already causing a huge impact.

The new Swift features that are spawning out it are also game changing, and I for one am ready for the addition of new compiler black magics into Swift.

Follow me on my Twitter (@rockthebruno), and let me know of any suggestions and corrections you want to share.

References and Good readsSE-0258: Property DelegatesOriginal Returnless Expressions PRFunction Builders Pitch.

. More details

Leave a Reply