-
Notifications
You must be signed in to change notification settings - Fork 1
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
feat: lazier runtime #27
Conversation
I managed to upgrade my codebase to melange and latest main of the plugin, it’s a fairly large app using generated protobuf bindings for calling grpc-web from browser, everything works correctly now. Runtime part also looked like a trivial change. I’d love this change to get accepted so as to allow usage in melange. |
Thanks for the PR and for looking into this. What exactly break melange? Is it the definition of the spec that causes problem (i.e. is the spec required to be lazy aswell?) Making the functions less "eager" is something that I've tried before, but it really impacted speed, so I would be happy if this could be made local to the code gen. i.e. controlled by a flag to Something like let serialize = lazy_opt ~lazy ~f:Internal'modules.Runtime.Serialize.serialize spec (where the value of lazy is taken from code gen options) The runtime can then define a function like: let lazy_opt: lazy:bool -> f:('arg -> 'v -> 'r) -> 'arg -> 'v -> 'r = fun ~lazy ~f arg ->
match lazy with
| false -> f arg
| true ->
let f' = Lazy.from_fun (fun () -> f arg) in
fun v -> (Lazy.force f') v (Edit: updated to allow the optimizer to do constant propagation) Also, consider reporting this to melange. |
And codegen would be controlled by something like |
Exactly. In the same way as specifying other options controlling the generated code as documented here |
And I'd like to avoid marking the signature of |
the smallest repro is something like the following, where you'll see module type Message = sig
val f : unit -> unit
end
module rec X : sig
val make : unit -> unit
val serialize : unit -> unit
end = struct
let make x = x
let serialize =
let f =
let (module Msg) = (module Y : Message) in
Msg.f
in
fun () -> f ()
end
and Y : sig
val f : unit -> unit
end = struct
let f = fun () -> ()
end
The underlying issue is that Melange compiles recursive modules to JS objects. It all works out if the modules don't have We're looking into this separately on the Melange side for sure, but I'd say it's a longer term, if ever, change. We added a test to track this behavior in melange-re/melange#1112. |
Thanks for the detailed description of the problem. Instead of using a flag to control the code-gen, is there a way to determine if the code is running under melange? Will If so, it would be possible to at runtime to apply lazy evaluation for backends other than |
Indeed |
I can attempt to make a simple solution by wrapping serializers and deserializers in a lazy eval that switches on Is there an easy way to test if this is working? I have no experience with running Melange. What is a good staring point for generating a test case for doing test driven development on this? |
I'm trying to add a simple melange test here, following the example from the dune documentation. When adding a dependency to
Any idea on how to resolve this? As I said, this is my first attempt at using melange. |
Melange libraries need However, adding I'm not sure that ocaml-protoc-plugin needs |
I create a branch, |
@andersfugmann I'll try this asap, thank you. |
@andersfugmann I tried your change and it works! Re-generated all bindings from that branch, tweaked the runtime, everything worked as expected. |
Thats great! I need to do some more testing (and solve a severe bug that I found in the process) before merging. Btw. Did you need to make changes to the runtime of |
@andersfugmann Yes, at the moment I do have to do that. I vendored in Melange requires dune libraries to have I wanted to play more with OPP runtime before suggesting changes to the upstream. |
Thanks for the clarification. I've released 6.1.0, which includes the lazy binding. The code still depends on both I will close this PR, as I think its super-seeded by #31. |
Spec.message
pass first-class modules to itUndefined_recursive_module
exceptionsI recently collaborated with @rauanmayemir to get his app ported to Melange, including running ocaml-protoc-plugin generated code, and this was the only required change.