generated message-types have only getters but no setters at the moment.
This makes it impossible to create an interface which can change values of them.
This would be especially useful for the return messages of rpc calls.
For example a generic function which adds an request-id to every response.
Nope. The code bloat does not warrant the minor utility, which you can achieve with your own wrapper types, or with reflection.
Are you sure we can't discuss this? I don't see this as minor, I have the exact same issue, want to set ResponseID from RequestID.
Alternatively, and this may already exist, could there be / is there already a way to add a hook for 'extra' parts like setters?
+1
@dsymonds With due respect, that's an obnoxiously terse response to a legitimate request. If it was so easy @ekle would not have asked. I expect you'll close the discussion next? This is typical golang community "you're a bad programmer for asking" behavior; we can be better than that.
Let's discuss this like engineers. In response to your assertions:
Manually writing wrappers for all messages is a terrible solution; generating them is marginally better but both are a large amount of non-trivial work for a problem easily and naturally solved in this library: Adding setters.
In the spirit of showing my work, this patch was sufficient to get my project moving again, and I was able to eliminate a lot redundant functions with a two line interface as a result.
@jspiro thats a cool patch. at the moment i'm using a big Makefile with some bash/grep magic to transform the existing getters to setters in a new file.
@jspiro, I don't think it's helpful to summarize @dsymonds as simply saying "you're a bad programmer for asking" since he says nothing of the sort. Even if someone closes the issue, you can always respond back with more discussion points as you have done here.
Points to consider:
proto.Message types are generated by protoc-gen-go, however there are some custom defined types that satisfy the proto.Message interface; it is not reasonable to expect them to setter methods (or even setter methods with the same signature). One of the core issues with the proto.Message interface is that it is marginally better than interface{}. It is trivial for any user-defined type to implement proto.Message, but the problem is that the proto package (and others) have no idea how to handle these custom types. The proper approach is to extend (this is a breaking change) the proto.Message interface to include reflection information about the protocol buffer itself. We're not talking about Go reflection, but a reflection interface designed specifically for protobuf. I will file a separate issue about this.libc)./cc @alandonovan, who is interested in protobuf reflection.
/cc @cherrymui, who is interested in the performance side of things.
See #364.
I've been working on #364 and I am convinced that is the right solution for the root issues going on here. I understand the temptation want to use Go interfaces to set some generic field in a set of messages, but it makes the very subtle assumption that all of them will have the same method signature, which is not a world we want to back ourselves into.
I ran into this issue today and wrote a little protoc generator for setters. Thought I'd share:
https://github.com/codyaray/proto-go-setter
Still a WIP. Right now it supports primitive types. Working on adding more complex types.
why dont you support setter.
how can i Abstract interface from many messages?
shall we write setter one by one and then Abstract the setter's interface?
and how can i use the interface feature of golang to protobuf messages?
We’re reworking the way proto reflection works, and it should support better abstract interactions with messages.
But typically Go prefers _less_ abstraction… maybe you’re trying to abstract too much?
i just abstract one public operation of one field of ten or more structures.
and proper abstraction is the way keep code simple, and interface abstraction is the main idea of golang?
proper abstraction, i mean just make code simple or good structure, i dont mean abstract everything.
my implemetion:
rpc input -> grpc server(internal Dispatch) -> grpc server impl (my code)->grpc server impl : routine (my code, i need abstruct common api to two field from different implemetion: int success, string errorMsg. )-> acturtal implemetion
i think abstract the two field is resonable.
for rpc suitiuation, we need keep rpc api/protocal stable. and implement different backend . so we dont want to expose different api set for different backend implemention.
or i must write much if/else in routine code for keeping only one api set without Setter interface.
these if/else are lots of duplicate code. that will make routine code complex and ugly.
i must make changes to each if condition when bug fixing or updating.
A central concept of golang is to _not abstract things unnecessarily_. In general, you should be avoiding adding layers of abstraction unless you find it extremely difficult not to. As such, each RPC should have a discrete, individual, and specific proto.Message input and output.
Having two fields success and errorMsg seems odd, considering that gRPC will pass any error from server to client. But even without using the capabilities that already exist in gRPC, repeating yourself is _not always a bad thing_. Being precise is far more important than building abstraction layers.
P.S.: If you have named your field errorMsg then you’re also breaking with the style guides for proto. The protobuf compiler will automatically convert your snake_case names into camelCase or CamelCase as the language style prefers: https://developers.google.com/protocol-buffers/docs/style#message-and-field-names
Most helpful comment
@dsymonds With due respect, that's an obnoxiously terse response to a legitimate request. If it was so easy @ekle would not have asked. I expect you'll close the discussion next? This is typical golang community "you're a bad programmer for asking" behavior; we can be better than that.
Let's discuss this like engineers. In response to your assertions:
Manually writing wrappers for all messages is a terrible solution; generating them is marginally better but both are a large amount of non-trivial work for a problem easily and naturally solved in this library: Adding setters.