-
Notifications
You must be signed in to change notification settings - Fork 64
Description
tl;dr: what is the reasoning why ProtoBuf.jl only generates immutable structs? Would you accept a PR to add support for mutable structs on top of the existing immutable structs?
Context
We (@Ochibobo and I) are building a way to call Google optimisation solvers from JuMP/MathOptInterface (jump.dev). The easiest way to do so it to serialise MOI models into the right proto (MathOpt, I know the name is confusing) and then call the solver from there.
Building protos by code can be cumbersome with immutable APIs, especially when you have many nested messages (see MathOpt). The design forces you to have another set of structs (mutable ones) that you maintain, so that you can build your deeply nested message. These mutable structs are basically the same as the generated code. While this makes sense when you can attach some behaviour to the copies that you make (if you have a MessageProto, you might want a Java class Message that has helper methods), that's not really a valid point in Julia (as you don't add methods to classes).
The pain point for us is that, to build a ModelProto, we need to copy the code that ProtoBuf.jl generates into a new mutable struct, say Model, then do the same for each and every message we need.
I very well understand that having a default implementation that is immutable is good. However, there are scenarios where it is simply painful beyond reason.
What others do
Many official ProtoBuf implementations have mutable and immutable APIs.
- In C++, you have both of them in the same generated code (with mutable accessors prefixed by
mutable_). - In Java, the internal version generates mutable classes with the
Mutableprefix; you can switch to the standard classes by usingmutableCopyorimmutableCopy; otherwise, you have the Builder interface (very cumbersome). - In JavaScript, JSPB (ProtoBuf implementation using JSON as wire format) has mutability by default (for historical reasons), with immutable messages prefixed by
Immutable(and a read-only interface backed by either mutable or immutable messages); like in Java, you have the methodstoMutableandtoImmutable. - Dart has a Builder-like interface for mutation.
Python and Go only have a mutable API.
Proposed change
We'd like to have mutable code generated alongside immutable one, like the internal Java example above. On top of struct Message, ProtoBuf.jl would generate mutable struct MutableMessage, so that we do not break existing users. We would generate methods like copy_to_mutable and copy_to_immutable to move from one type to the other.
We could work on the implementation of this change.
Links
MathOptInterface/MOI: https://github.com/jump-dev/MathOptInterface.jl/
OR-Tools (which includes MathOpt): https://or-tools.dev