Reputation: 2727
I am trying to share a large dictionary/map between a client and a service. I need to be able to bidirectionally set values, and delete values from the dictionary/map without passing the entire map back and forth each time.
I know I can create a map using:
map<string, CustomType> cells = 3;
I see a sugestion to use oneof here: https://github.com/google/protobuf/issues/1606
However, the syntax suggested in that bug report doesn't make sense to me:
message Test1 {
oneof a_oneof {
int32 a = 1;
}
}
How would I test for that? How would I store None?
I would try to create something like:
message None{}
message MaybeCustomType{
oneof maybe{
CustomType just = 1;
None none = 2;
}
}
But I'm not at all convinced that this is the elegant and correct solution.
I also considered changing my schema entirely and doing.
map<string, CustomType> cells = 1;
repeated string deleted_cells = 2;
However I don't like that solution because it creates an undefined case. What happens if a cell named "foo" appears in both the "cells" map and the "deleted_cells" map? Furthermore, it abstracts the data away from the computation. I'd like to be able to pass a cell to a function which modifies and potentially decides to delete the cell, and so it seems natural to me that information about cell deletion be stored near the cell itself.
Upvotes: 4
Views: 2414
Reputation: 1428
Your language tag mentions haskell but I'm not sure which library implementation you're using to provide proto3 support, so I'll try to provide a generic answer.
The thread you pointed to suggests using oneof
with a single field since it's possible to represent a null
(really the absence of the field). Fortunately you don't need to create a None
type for this purpose since it is built into the language-specific generated source files. Take a look at the Language Guide for oneof...
You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.
The "if any" part is the magic you're looking for. The generated C++ code for a oneof definition will provide a special oneof_name_case()
method that will tell you if one of the fields have been set...
OneofNameCase oneof_name_case() const: Returns the enum indicating which field is set. Returns ONEOF_NAME_NOT_SET if none of them is set.
A similar method is generated for Java code: getOneofNameCase()
returns ONEOFNAME_NOT_SET
if none of the oneof fields are set.
Starting from a test message...
message Test1 {
oneof single_field_oneof {
int32 some_int = 1;
}
}
If you were using C++ you could use code similar to the following to handle the oneof field...
int main(int argc, char* argv[]) {
Test1 test;
// <Populate message somehow>
if (test.single_field_case() == Test1::kSomeInt) {
std::cout << "Field is set, value is " << test.some_int() << std::endl;
} else {
assert(test.single_field_case() == Test1::SINGLE_FIELD_NOT_SET);
std::cout << "Field is not set" << std::endl;
}
}
Anyway, as I mentioned I'm not familiar with the specific proto3 language bindings for Haskell, but the oneof
feature should have similar functionality in the library that you're using.
Upvotes: 1