Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple ppx annotations for one type? #194

Open
Lupus opened this issue Mar 15, 2023 · 2 comments
Open

Multiple ppx annotations for one type? #194

Lupus opened this issue Mar 15, 2023 · 2 comments

Comments

@Lupus
Copy link
Contributor

Lupus commented Mar 15, 2023

I'm trying to build a flow with some validation of protobuf types for my Twirp generator (proprietary, uses custom binary to manipulate the compilerlib library of ocaml-protoc). The most optimal way that I found is to transform some per-field options from protobuf spec into ocaml_type_ppx, that is further processed by ocaml-protoc and resulting annotation gets emitted along with generated OCaml types. compilerlib provides me with grouped protos, that I traverse to collect per-field validation rules and emit single deriving annotation with all the rules passed as the arguments. But when I tried to implement the actual ppx to generate the validation code - I ran into an issue with recursive types. Only one type out of recursive group needs to have the deriving annotation, otherwise ppxlib calls the deriver multiple times for a whole group or recursive types. See this discuss thread for more context. The proposed solution is to have only one deriving annotation per group of recursive types and encode rest of validation metadata in custom annotations to each type. This works well with ppxlib, but requires an ugly hack - I'm passing several ppx annotations via ocaml_type_ppx concatenating them with ][@@ in an SQL injection style... I doubt that's the designed way to add multiple ppx to single type, although it works right now. Wanted to discuss if this is good enough and will likely work in future versions, or some separate API might be implemented to allow multiple ppx annotations to be specified for resulting OCaml type in a clean way.

Why ppx for validation in first place? I tried to find a way to implement custom codegen on top of compilerlib alone, but that seems to be quite complicated. One of the goals is to mark certain fields as required, so that there are no option wrappings in the resulting types. So for every message type I want to generate a type that is the same or a bit different with some functions to go from one to another. And code for generating types is large and depends on compilerlib internals that are not feasible to be exported as some public API. So I decided to pass some annotations down to OCaml types instead and handle them via ppx for the boilerplate codegen. This model gives somewhat clean separation of concerns.

@c-cube
Copy link
Collaborator

c-cube commented Aug 8, 2023

I don't have time for this right now, but I'd certainly be interested in a PR.

There could be a -ocaml_deriving_ppx option that can be repeated, like so:

$ ocaml-protoc foo.pb -ocaml_deriving_ppx "show {with_path=false}" -ocaml_deriving_ppx eq

and it's collect all the deriving arguments into one [@@deriving show {with_path=false}, eq]?

@Lupus
Copy link
Contributor Author

Lupus commented Aug 9, 2023

So far we have a workaround in our binary, that's using the compilerlib. Once it breaks, maybe we'll invest into a better solution 😁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants