simonboots
(Simon Stiefel)
1
I've been playing around with result builders a bit. I was thinking of using ExpressibleByStringLiteral to convert a string literal into MyComponent but got hit by a "Cannot convert value of type MyComponent" error.
Is there something I am missing? It seems like the ExpressibleBy*Literal set of protocols would be a great fit for result builders.
enum MyComponent {
case null
case string(String)
}
@resultBuilder
struct MyBuilder
{
static func buildBlock(_ components: MyComponent...) -> MyComponent {
if let firstComponent = components.first {
return firstComponent
} else {
return .null
}
}
}
extension MyComponent: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
self = .string(value)
}
}
extension MyComponent {
init(@MyBuilder build: () -> MyComponent) {
self = build()
}
}
func testItworks() {
let component = MyComponent {
"A String" // Error: Cannot convert value of type MyComponent
}
}
Thanks,
Simon
Result builder type inference seems to be a bit weaker, so I'm not sure if this is another example of that.
I think you might be able to instead write an overload of buildExpression that takes a string:
extension MyBuilder {
static func buildExpression(_ expression: String) -> MyComponent {
.string(value)
}
}
2 Likes
Jumhyn
(Frederick Kellison-Linn)
3
Yeah, IIRC, the buildBlock transform basically does this:
let component = MyComponent {
"A String" // Error: Cannot convert value of type MyComponent
}
gets turned into:
let component = MyComponent {
let _partialResult1 = buildExpression("A String")
let _block = buildBlock(_partialResult1)
return buildFinalResult(_block)
}
where buildExpression and buildFinalResult may be omitted if the builder in question doesn't implement them. So the type of the components in buildBlock can't directly influence the inference of the individual partial results. You can see that also here:
@resultBuilder
struct B {
static func buildBlock(_ components: [Int]...) -> [Int] {
components.first!
}
}
func build(@B _ block: () -> [Int]) -> [Int] {
return block()
}
build {
[] // Error, cannot convert '[Any]' to '[Int]'
}
but if we add the builder function
static func buildExpression(_ expression: [Int]) -> [Int] {
expression
}
then everything works as expected.
3 Likes
simonboots
(Simon Stiefel)
4
That makes sense, thanks for the help @stephencelis and @Jumhyn !