Eric Blake <ebl...@redhat.com> writes: > On 05/14/2018 01:08 PM, Markus Armbruster wrote: >> Anton Nefedov <anton.nefe...@virtuozzo.com> writes: >> >>> The patch makes possible to avoid introducing dummy empty types >>> for the flat union branches that have no data. >>> > >> >> Some unions have no variant members for certain discriminator values. >> We currently have to use an empty type there, and we've accumulated >> several just for the purpose, which is annoying. >> >> QAPI language design alternatives: >> >> 1. Having unions cover all discriminator values explicitly is useful. >> All we need is a more convenient way to denote empty types. Eric >> proposed {}, as in 'foo: {}. > > And even posted a patch for it once: > https://lists.gnu.org/archive/html/qemu-devel/2016-07/msg00311.html > > although it was late enough in that series with other churn in the > meantime that it would need serious revisiting to apply today. > >> >> 2. Having unions repeat all the discriminator values explicitly is not >> useful. All we need is replacing the code enforcing that by code >> defaulting missing ones to the empty type. >> >> 3. We can't decide, so we do both (this patch). >> >> Preferences? > > Here's some tradeoffs to consider: > > Allowing 'foo':{} makes your intent explicit - "I know this branch of > the union exists, but it specifically adds no further members".
Yes. > But > it's a lot of redundant typing - "I already had to type all the branch > names when declaring the enum type, why do it again here?" Redundancy isn't bad per se, but it needs to serve a useful purpose. What's the purpose of repeating the tag values? You give one below: grep. > Allowing an easy way to mark all non-listed members of an enum default > to the empty type is compact - "I told you the enum, so you are > permitted to fill in an empty type with every branch that does not > actually need further members; and I had to opt in to that behavior, > so that I purposefully get an error if I did not opt in but forgot an > enum member". Syntactic options aren't bad per se, but they need to serve a useful purpose. What's the purpose of having both unions that require all tag values, and unions that default omitted tag values to "no variant members"? > But if the enum is likely to change, it can lead to > forgotten additions later on - "I'm adding member 'bar' to an enum > that already has member 'foo'; therefore, grepping for 'foo' should > tell me all places where I should add handling for 'bar', except that > it doesn't work when handling for 'foo' was implicit but handling for > 'bar' should not be". If your code still compiles when you forget to add members to a struct or union, you obviously don't need the members you forgot :) For what it's worth, grepping for the enum type's name finds the union just fine, and is less likely to find unrelated stuff. > Having said that, my personal preference is that opting in to an > explicit way to do less typing ("all branches of the enum listed here > are valid, and add no further members") seems like a nice syntactic > sugar trick; and the easiest way to actually implement it is to > probably already have support for an explicit 'foo':{} branch > notation. That way, you can always change your mind later and undo > the opt-in "data-partial" flag and rewrite the union with explicit > empty branches when needed, to match how the sugar was expanded on > your behalf. Is that 1. combined with 3.? I dislike 3. because I feel it adds more complexity than the other options. More apparent once you add the necessary test coverage (another reason why requiring test coverage is such a good idea; having to cover every bell & whistle tends to make people reconsider which ones they actually need). I'd prefer a more opinionated design here. Either we opine making people repeat the tag values is an overall win. Then make them repeat them always, don't give them the option to not repeat them. Drop this patch. To reduce verbosity, we can add a suitable way to denote a predefined empty type. Or we opine it's not. Then let them not repeat them, don't give them the option to make themselves repeat them. Evolve this patch into one that makes flat union variants optional and default to empty. If we later find we still want a way to denote a predefined empty type, we can add it then. My personal opinion is it's not.