I just can’t get my head around this reasoning, it’s just as valid to ask for/return a “foo OR bar” as it is to ask for a “foo AND bar”. Any protocol that rejects that pushes that complexity elsewhere, somewhere less explicit.
message Filter {
oneof kind {
Tags tags = 1;
IPRange ipRange = 2;
}
}
With this in place, a client has to check the type of the filter in order to access the actual filter: switch t := f.Kind.(type) {
case *Tags:
// ...
case *IPRange:
// ...
}
Without it, you can get into a situation where it's possible to create invalid combinations: message Filter {
string type = 1;
Tags tags = 2;
IPRange ipRange = 3;
}
Now you can accidentally end up with code like this: f = Filter{}
f.Type = FilterType_Tags
f.IPRange = IPRange{}
or: if f.Type == FilterType_Tags {
useFilter(f.IPRange)
}1. It enhances readability 2. It would be a surprise to you: oneof actually enhances type safety. It is just lacking type system of Go where you cannot express the feature and thus loses type safety.