So I have run into this a few more times, and I think I have a proposal for a good solution to at least part what makes working with oneofs hard.
One of the main problem with the oneof fields, for me, is that there is no simple way to access the "value" field of the non-empty members. You essentially have to check that it's not empty, then figure out what its real type is and cast it to that simply so that you can then access the real value. A really simple addition here that would make things quite a bit simpler would be a "getValue" method on the generated trait which returns an Option[GeneratedMessage]. Even better, would be if during codegen all types in the oneof were assigned a trait like "Valued<oneofname>" so that the return type of "getValue" can be more specific. I'm not sure if that violates some codegen ordering rules, so maybe that's not doable, but it'd help.
To illustrate why this would be nice with an example:
message TaskHolder {
bytes id = 1 [(scalapb.field).type = "java.util.UUID"];
int32 pending_cl = 2;
oneof task {
TaskA a = 4;
TaskB b = 5;
TaskC c = 6;
... etc etc ...
}
}Now let's say TaskB and TaskC both inherit from some trait indicating they are cancellable tasks, for example. With the current codegen, if I want to check if the task inside a task holder is a cancellable task, I really don't have any way to do that besides a big matcher with an option for every task type. With my proposed changes, I could just do:
tholder match {
case TaskHolder(_, _, t) if t.getValue.map(_.isInstanceOf[CancellableTask]) => true
case _ => false
}
Still not the prettiest thing ever, but a lot less code than a big match with every task type.
Does that seem good? Maybe there's a better option? I'd be happy to make a PR with the change, although it might be quite some time before I can get around to it :).
Thanks!
Spencer