Is there a summary of AST changes and what needs to be done to migrate old PPXs to the v11?
There’s no proper write up AFAIK but here are a few resources:
- ppx_spice migrates to support v11: Support uncurried on v11 by mununki · Pull Request #49 · green-labs/ppx_spice · GitHub
- rescript-relay migrates to support v11 (this is a bit simplified though because it doesn’t need to care about more than arity 1): Uncurried by zth · Pull Request #449 · zth/rescript-relay · GitHub
Also check these compiler files for more info about what has changed, and potential utils you can copy to your project to ease the transition:
So far, the changes I had to make to build examples with the updated ppx can be summarized as follows:
let f = @res.arity(2) (a, b) => a + b // annotate function definitions
let x = @res.uapp f(1, 2) // annotate function calls
I annotated all the generated function definitions and function calls, and it worked. However, I haven’t fixed the test suit yet and haven’t run any code, so maybe I’ll discover something else.
P.S. In the linked PRs, @res.optional
and @res.partial
attributes are also mentioned, but I haven’t needed them so far.
Are @res.arity
and @res.uapp
documented anywhere?
I see that they’re in the Rescript compiler source code. I know the purpose of the @res.arity decorator, to tell the compiler what we expect the arity of the function to be, but I don’t know the actual behavior. If I have a function with 4 params, and I decorate with @res.arity(2), will the first two params be treated as a single function, and the last two params become curryable? In any case, I expect that my fix will be to always have the arity match the number of args in order to make uncurried functions.
The @res.uapp decorator, is that the inverse companion? Is this telling Rescript to package all of the function parameters up as a single tuple on the backend function invocation?
I’ve never authored a PPX from scratch before, but I’m trying to update one to work with Rescript 11, hence the questions. Thanks for your patience.
@alex.fedoseev the examples you wrote above are in Rescript, but that’s not what your PPX actually does under the hood, right? It seems to me like the PPX runs on the OCaml AST level, after Rescript has parsed and transformed the syntax but before the compiler is run, but I’m not sure.
Your tips on your workflow for upgrading your PPX were helpful. Thank you!
I am also converting graphql-ppx
right now, and I used some of the examples. I applied the attributes to the function declaration and the application where relevant and it seems to pass tests. I still have to test it in our codebase though to make sure it actually works (probably not yet ). The PR is here, so that might also help your changes.
I think my intuitive answer as to why we need to annotate the arity in the function declaration is that it is to differentiate between let fn = a => b => a +b
and let fn = (a, b) => a+b
which might otherwise not be different in the parse tree representation. There are no such thing as multi arity functions in the OCaml parse tree, and ReScript achieves this by annotating. I guess the compiler then checks if the arities actually match with the application as an extra check in uncurried mode. If this all matches up, rescript can emit clean function applications and doesn’t have to do any runtime curry polyfill.