The trouble is you can only have one self parameter, and closures cannot have self parameters (unless captured). You would have to outline all of your closures as extensions on the builder class / struct. You would also run into trouble if you wanted a builder function to be a method on another struct / class.
Interesting approach to a DSL.
Maybe was hoping that Swift gets a macro system instead on which DSLs could be built.
(Maybe along these lines: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.859&rep=rep1&type=pdf)
But this is definitely a bigger endeavour.
Good points. I'll think on it.
One problem I have with the proposal is that it tends to force implementors to define functions for child nodes that litter the global namespace. Has a solution been considered where the compiler tries to resolve child nodes (p, div, Text, View) as functions and properties of the builder?
I wonder if an alternative has been considered where thereās an implied āselfā inside the closure, which is a kind of builder instance on which one could define and scope these functions?
If I understand correctly, Kotlin does something to that effect.
Sorry if these have already been asked. I read through the thread and didnāt see them... apologies if I missed something.
How would this proposal be different if we had Variadic Generics? How would SwiftUI be different? Assuming we get VG, how possible would it be have backwards compatibility with older versions of a library which implements the current āmany overloads of the same function with different aritiesā technique?

[this proposal] tends to force implementors to define functions for child nodes that litter the global namespace
This was my biggest concern as well. I was hoping each call could be an initializer of some kind instead:
struct HTML: Tag { ... }
...
let doc = HTML {
Meta { }
P { "The quick brown fox..." }
Img { "https://.../dog.png" }
}
But the properties idea is just as good. I'm kind of upset this is only being discussed after it was used by Apple in an official manner.
I do discuss the lookup issue in the proposal, but mainly Iād like to remind people that HTMLBuilder
is not, in fact, being proposed.

How would this proposal be different if we had Variadic Generics? How would SwiftUI be different? Assuming we get VG, how possible would it be have backwards compatibility with older versions of a library which implements the current āmany overloads of the same function with different aritiesā technique?
the whole 11 <C1,C2,C3...CN> overloads thing would be unnecessary, as one type-variadic implementation could handle an arbitrary number of heterogenous views. there would not be backwards compatibility, but SwiftUI isn't part of the standard library, and so isn't subject to Swift ABI stability.
that being said, variadic generics have been "just on the horizon" for 2 or 3 years now, so i would manage my expectations if i was you
This is exciting!
About the global namespace pollution problem.
If we define the node building functions in your example (div
, body
...) in the HTML protocol, wonāt we be able to use them in the function closure through an implicit member expression (.div
)? If so, what are the drawbacks of this approach?
EDIT:
This is explained in the proposal
Contextual lookups like
.p
will generally not work at the top level in DSLs because they will be interpreted as continuations of the previous statement.

I do discuss the lookup issue in the proposal, but mainly Iād like to remind people that
HTMLBuilder
is not, in fact, being proposed.
Hi John. I don't think anybody is discussing the HTMLBuilder
implementation. We're just using it as example for the proposal.
When you say you discuss the lookup issue int the proposal, do you mean this?
It is common for DSLs to want to introduce shorthands which might not be unreasonable to introduce into the global scope. For example,
p
might be a reasonable name in the context of ourHTMLBuilder
DSL, but actually introducing a global function namedp
just for DSL use is quite unfortunate. Contextual lookups like.p
will generally not work at the top level in DSLs because they will be interpreted as continuations of the previous statement. It would be good if there was some way for the DSL to affect lexical lookup within transformed functions (although this might be unfortunate for features like code-completion and diagnostics).
But I'm not suggesting "Contextual lookups like .p
". I'm suggesting that:
div {
if useChapterTitles {
h1(chapter + "1. Loomings.")
}
p {
"Call me Ishmael. Some years ago"
}
p {
"There is now your insular city"
}
}
is transformed into:
div {
var v0_opt: [HTML]?
if useChapterTitles {
let v0: [HTML] = HTMLBuilder.buildExpression(HTMLBuilder.h1(chapter + "1. Loomings."))
v0_opt = v0
}
let v0_result = HTMLBuilder.buildOptional(v0_opt)
let v1 = HTMLBuilder.buildExpression(HTMLBuilder.p {
"Call me Ishmael. Some years ago"
})
let v2 = HTMLBuilder.buildExpression(HTMLBuilder.p {
"There is now your insular city"
})
return HTMLBuilder.buildBlock(v0_result, v1, v2)
}
Basically, I'm asking if its feasible for the generator in the compiler to do lookup of identifiers in the block as static functions or properties on the builder type.
How about this design, that addresses:
- Supporting stateful builders
- Namespacing builder members to avoid global namespace pollution
return build HTMLBuilder { builder in
div {
if useChapterTitles {
h1(chapter + "1. Loomings.")
}
builder.someInstanceState = "some example value" // An instance property that would need to exist on `HTMLBuilder`.
p {
"Call me Ishmael. Some years ago"
}
p {
builder.someInstanceState // retrieve the value
}
}
}
- The
build
keyword, as mentioned earlier, signals "here be magic language dragons" - A new
HTMLBuilder
instance is initialized for this call, which can be used to store and retrieve state. - The
static
functions onHTMLBuilder
have been replaced with instance methods, which have access to the state of the newly initializedHTMLBuilder
(althoughHTMLBuilder
isn't a good demonstration for this, since it would be stateless anyway) - The
p
,h1
,div
, etc. global functions have been moved to be instance methods onbuilder
. They also gain access to that state.- Symbol look up within this region follows the regular look-up rules, unless it can't find the symbol (e.g.
p
, in which case it will tryHTMLBuilder.p
)
- Symbol look up within this region follows the regular look-up rules, unless it can't find the symbol (e.g.
- The outermost closure provide a clearly delineated scope of influence of this magic. Further, it introduces a clear way for the
HTMLBuilder
instance to be introduced into the source code (even allowing a developer-specified name, rather than hard coding some magic keyword).
This would transform into:
var builder = HTMLBuilder()
builder.div {
var v0_opt: [HTML]?
if useChapterTitles {
let v0: [HTML] = builder.buildExpression(builder.h1(chapter + "1. Loomings."))
v0_opt = v0
}
let v0_result = builder.buildOptional(v0_opt)
builder.someInstanceState = "some example value"
let v1 = builder.buildExpression(builder.p {
"Call me Ishmael. Some years ago"
})
let v2 = builder.buildExpression(builder.p {
builder.someInstanceState
})
return builder.buildBlock(v0_result, v1, v2)
}
That is ordinary lexical lookup, which is what the paragraph is about. Iāll revise.

How about this design, that addresses:
- Supporting stateful builders
- Namespacing builder members to avoid global namespace pollution
The move from static functions to instance functions doesn't allow the builder type to be generic on the "nodes", which SwiftUI
requires.

That is ordinary lexical lookup, which is what the paragraph is about. Iāll revise.
Is that an answer to my following question? If yes, I don't think I understand the answer.

Basically, I'm asking if its feasible for the generator in the compiler to do lookup of identifiers in the block as static functions or properties on the builder type.
Hey David,
I'm not quite catching on, if the static functions can be generic why can't the instance methods?
The instance methods can be generic, but SwiftUI requires the builder type to be generic. SwiftUI uses type inference to infer those generic types through the factory static function.
Iām saying that that section is meant to have already answered your question: I think it might be interesting, but I donāt know if itās feasible, which is why itās listed as a possible future direction.
So, I've been playing around with SwiftUI, the primary reason this currently exists, and it appears that there's no support for switch
statements or for
/while
loops? Is this only a current limitation or is this by design?
Yes, they're listed in Future Direction.
Edit:
I'm sure for
is not supported, but I get a gist that switch
should be supported, may need someone to confirm switch
one.