Virtualized Abstract Syntax Trees (ASTs)
One of the things mentioned in future directing of the result builder proposal is the virtualization of control flows so I went ahead and implemented for, if and switch.
buildVirtualFor
This one is pretty straightforward, I just added on more closure to where clauses.
static func buildVirtualFor<S: Sequence, BodyReturn>(
_ sequence: () -> (S),
_ body: (S.Element) -> BodyReturn,
_ isIncluded: (S.Element) -> Bool
)
Example:
for i in 1...10 where i.isMultiple(of: 2) {
"\(i)"
}
buildVirtualFor(
{ 1...10 },
{ i in "\(i)" },
{ i in i.isMultiple(of: 2) }
)
buildVirtualIf
This one is a little bit tricky because at first sight a closure that returns a Bool seems a goot fit for the if conditions but because optional binding that's not enough so I choose an approach where the conditions closure returns Void or a Tuple of N elements if there's any optional binding. If all conditions are not satisfied, the closure returns nil. Theses two scenarios are represented by a ConditionsReturn? type. A then closure receives ConditionsReturn and returns ThenReturn and else just returns ElseReturn and it's an optional closure.
static func buildVirtualIf<ConditionsReturn, ThenReturn, ElseReturn>(
_ conditions: () -> ConditionsReturn?,
_ then: (ConditionsReturn) -> ThenReturn,
_ else: (() -> ElseReturn)?
)
Examples:
if Bool.random() {
"then"
} else {
"else"
}
buildVirtualIf(
{ if Bool.random() { return () } else { return nil } },
{ () in "then" },
{ "else" }
)
if Bool.random() {
"then"
}
buildVirtualIf(
{ if Bool.random() { return () } else { return nil } },
{ () in "then" },
Optional<() -> Never>.none // nil is not sufficient here because `ElseReturn` requires a concrete type
)
let x: Int? = 0
let y: Int? = 0
if let x, let y {
"\(x), \(y)"
}
buildVirtualIf(
{ if let x, let y { return (x,y) } else { return nil } },
{ (x,y) in "\(x), \(y)" },
Optional<() -> Never>.none
)
This basic buildVirtualIf can be expanded to if expressions with one or more else if using parameter packs.
static func buildVirtualIf2<each ConditionsReturn, each ThenReturn, ElseReturn>(
_ then: repeat (conditions: () -> (each ConditionsReturn)?, body: (each ConditionsReturn) -> (each ThenReturn)),
else: (() -> ElseReturn)?
)
buildVirtualSwitch
This one follows pretty much the same logic of a buildVirtualIf with a variadic number of conditions and bodies , but the conditions receive Subject as their input.
static func buildVirtualSwitch<Subject, each ConditionReturn, each CaseReturn, DefaultReturn>(
_ subject: () -> Subject,
_ cases: repeat (condition: (Subject) -> (each ConditionReturn)?, body: (each ConditionReturn) -> (each CaseReturn)),
default: (() -> DefaultReturn)?
)
Examples:
switch Int.random(in: 1...5) {
case 1:
"1"
case 2:
"2"
default:
"3...5"
}
buildVirtualSwitch(
{ Int.random(in: 1...5) },
({ if case 1 = $0 { return () } else { return nil } }, { _ in "1" }),
({ if case 2 = $0 { return () } else { return nil } }, { _ in "2" }),
default: { "3...5" }
)
switch E.random() { // `E` is a enum with `c1`, `c2`, and `c3(Int)` cases
case .c1:
"CASE 1"
case .c2:
"CASE 2"
case .c3(let value):
"CASE 3 = \(value)"
}
buildVirtualSwitch(
{ E.random() },
({ if case .c1 = $0 { return () } else { return nil } }, { _ in "CASE 1" }),
({ if case .c2 = $0 { return () } else { return nil } }, { _ in "CASE 2" }),
({ if case .c3(let value) = $0 { return (value) } else { return nil } }, { (value) in "CASE 3 = \(value)" }) ,
default: Optional<() -> Never>.none
)
BTW, didn't know that if case x = 1 { } was a thing. It's weird but it made the implementation easy.
That's it for today! I will update the repository with these new build methods soon.