Hi Douglas,
Is there a way to have a debug mode that will output the translated code you showed? or some way to see this intermediate step would be great.
Thank you,
Chéyo
Hi Douglas,
Is there a way to have a debug mode that will output the translated code you showed? or some way to see this intermediate step would be great.
Thank you,
Chéyo
I don't think there's any way to get at the actual source of the builder-transformed code (since we don't have a general utility for going backwards from AST to source code), but if you run swiftc -dump-ast file.swift
, the generated output is post-typecheck (and so also post-builder-transform). If there's a better way to view the output of the function builder transformation, I'd love to know as well!
@beccadax has a tracing function builder. As for the compiler, if someone went ahead and implemented pretty-printing for expressions, you could use its AST-printing facilities to see what's happening.
Doug
Hey. Didn't read the entire conversation, but the proposal itself. Any reason why declarations are left alone by the transformation? The only reason I can find in the proposal is: "This allows developers to factor out subexpressions freely to clarify their code, without affecting the function builder transformation." Imho it should be left to the DSL in question to decide wether to allow people to factor out declarations. There are enough other ways to factor out code, but I could imagine reasonable usecases and an appropriate buildDeclaration
for such a transform...
Edit:
To elaborate: Say, we declare a variable a
. What the transformation has to do now is to wrap the entire scope where a
is available into a closure and pass a somehow transformed a
to that closure. That is, all you need is a
static func buildDeclaration(expr: GivenType,
continuation: @escaping (NewType) -> Component)
-> Component
In the DSL, the declared variable will then be inferred to have type NewType
rather than GivenType
.
Usecase:
static func buildDeclaration<T,U, E : Error>(expr: Result<T,E>,
continuation: (T) -> Result<U,E>)
-> Result<U,E>{
expr.flatMap(continuation)
}
and now assuming we use a functionbuilder
with the above method to create a constructor for Result
itself, the callsite could look like this:
Result(42){int in
let a = someFuncReturningResultA(int)
let b = someFuncReturningResultB(a)
someFuncReturningResultC(int,a,b)
}//Result<C,Error>
Edit edit:
Of course, you can support multiple such buildDeclaration
functions as long as lookup is unique. In above scenario, you may want to have another buildDeclaration
like
static func buildDeclaration<T,U, E : Error>(expr: T,
continuation: (T) -> Result<U,E>)
-> Result<U,E>{
continuation(expr)
}
which is essentially the default-implementation if there's no type-transformation from expr
to the input of continuation
, i.e. if we define that declaring a buildDeclaration
that does some type transformation just doesn't override the default implementation, we may not even need to write this extra code.
You may have ended up reading outdated documents @Anachron.
This is the "pitch thread", while the feature now known as "result builders" has already been accepted (after revisions): SE-0289 (review #2): Result Builders - #141 by compnerd so refer to that thread what the status quo is.
What you are mentioning with buildDeclaration
sounds to me exactly like the feature I mentioned early on when working on some internal DSLs, and it's right now in the "future directions" section:
The full motivation post is here: Function builders and "including" let declarations in built result