On 2/7/19 12:56 AM, Markus Armbruster wrote: > Max Reitz writes: > >> This patch allows specifying a discriminator that is an optional member >> of the base struct. In such a case, a default value must be provided >> that is used when no value is given. >> >> Signed-off-by: Max Reitz >> --- > I'm afraid this could become awkward later on. Let me explain. > > In many programming languages, absent optional arguments / members > default to a default value specified in the declaration. Simple. > > In others, 'absent' is effectively an additional value. The code > consuming the argument / member can interpret 'absent' however it wants. > It may eliminate the additional value by mapping it to a default value, > but it can also interpret 'absent' unlike any value. If there's more > than one consumer, their interpretations need not be consistent. The > declaration provides no clue on semantics of 'absent'. > > QAPI is in the latter camp. I trust you can already sense how much I > like that. > > Now you want to permit optional variant discriminators. As per general > rule, their interpretation is left to the code consuming it. One > instance of such code is the generated union visitor, which needs to > decide which variant to visit. Your default-variant tells it which > variant to visit. Other code interpreting the discriminator better be > consistent with that, but that's the other code's problem. Hmm. > > If I could go back in time, I'd flip QAPI to "'absent' defaults to a > default value". Lacking a time machine, we're stuck with cases of > "'absent' means something you can't express with a value" and "'absent' > means different things in different contexts" that have been enshrined > in external interfaces. Is there anything we could do to improve > matters for saner cases? > > I think there is: we could provide for an *optional* default value. If > the schema specifies it, that's what 'absent' means. If it doesn't, all > bets are off, just like they are now. And we already have the planned syntax, thanks to our recent work on adding conditionals - where we now have: { '*field': 'mytype' } we can also do long-hand: { { 'name': '*field', 'type': 'mytype' } } which also lends itself well to declaring a default: { { 'name': '*field', 'type': 'mytype', 'default': 'xyz' } } > > Say we do that (for what it's worth, introspect.json is already prepared > for it). How would it play with your default-variant? > > If an optional discriminator specifies a default value, then that's the > default variant. But wait, if there's also a default-variant, *that's* > the default variant! Awkward clash. To resolve it, we could either > forbid combining the two, or rule default-variant overrides the default. > Feels needlessly complicated. > > Could we get away with "if you want a default variant, the discriminator > must specify a default"? I like the idea. It means finally biting the bullet and implementing default values, but we've known we've wanted them for a while (as evidenced by the existing introspection output, and by the syntax that we have ready to put into use for it). It means that representing the default variant in a union now depends on the base class declaring a default for the optional parameter (that is, an optional parameter can only be used as discriminator if it has a declared default), and gives us variable defaults in more uses than just unions. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org