When I first saw SwiftUI, I instantly wondered how it was possible. It didn’t look like Swift. This foreign syntax was extremely expressive compared to UIKit. What used to take a ridiculous amount of UIKit code and possibly a storyboard, now takes ≤6 lines of code:
SwiftUI’s declarative syntax is made possible by function builders (here’s the proposal). This is what allows you to combine and compose views together (e.g.,
HStack taking two
Views and forming a
TupleView). Function builders are a huge step forward in Swift supporting declarative programming, and provide the basis for tons of powerful new DSLs.
I’ve been messing around with them lately, and I recently released a DSL for making HTTP requests. I learned a lot about function builders along the way. I hope the information I’ve included here can help you create your own DSLs.
Using a function builder
Let’s take a look at using the
ViewBuilder that powers SwiftUI’s DSL:
Let’s break it down:
@ViewBuilder function builder is applied to a function that converts two
Text views into a
TupleView that contains both
We don’t need a return statement because of SE-0255, which allows for implicit returns.
What the compiler does is convert our function into this:
As you can see,
ViewBuilder does all the heavy lifting. It takes in our views and creates the TupleView. You can use your own function builders in the same way. Let’s look at an implementation of a function builder.
As of Swift 5.1 in Xcode 11 beta 4, we need to use
@functionBuilder. This will be changing once the full proposal is implemented and accepted.
What our function builder does is take in strings, and return those strings with “Hello” inserted at the beginning.
When we use our function builder, the
buildBlock function is called, and it takes in any strings we pass. This is due to the variadic parameter (
String… , like how
buildBlock function we can perform any logic we need to create our String array. In this case, we add “Hello” to the beginning.
Creating a function builder
There are endless possibilities when it comes to function builders we could make. I decided a good way to start would be something simple and useful:
In Swift, creating an attributed string can be a real pain. Wouldn’t it be nice if we could use SwiftUI style syntax?
We can create a function builder to do just that. Let’s start with our builder:
Here we define our function builder and the standard
buildBlock . In this case, we take in multiple attributed string “segments”. Then we loop through them to create one combined string.
You can treat
NSAttributedString...as an array
We want our function builder to work when initializing an
NSAttributedString so we need to create a convenience initializer.
Now we’re ready to use our builder. However, to make the process even more seamless, I’ve created extensions for
NSAttributedString to add modifiers. You can get the code for those here.
Ok, let’s try out our function builder:
That’s all it takes to create a function builder. However, you may notice this doesn’t work in certain instances. With SwiftUI you may see something like this:
However, if you try to do something similar with our function builder, you’ll run into this error:
closure containing control flow statement cannot be used with function builder 'AttributedStringBuilder'
More build functions
To extend the functionality of your builder, you need to implement more static functions. The full proposal will support the following:
buildExpression(_ expression: Expression) -> Component
buildBlock(_ components: Component…) -> Component
buildFunction(_ components: Component…) -> Return
buildDo(_ components: Component…) -> Component
buildOptional(_ component: Component?) -> Component
buildEither(first: Component) -> Componentand
buildEither(second: Component) -> Component
I will update this article as these become available. Currently, we can use
As of Xcode 11 beta 4,
Build optional allows optional values to be included in the block. This includes if statements, which upon being false will return
Here’s a simple implementation to handle the possible
So there you have it. Swift 5.1 function builders (in their current state). I can’t wait to see what DSLs pop up in the next few months. If you make something cool, add it to the list of awesome-function-builders. I’m excited to see what you all create!
You can view the finished code here.
If you’ve found this article helpful, clap! Follow me so you don’t miss any of my articles on iOS development.