All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: qemu-devel@nongnu.org, famz@redhat.com, wenchaoqemu@gmail.com,
	lcapitulino@redhat.com
Subject: Re: [Qemu-devel] [PATCH v5 06/28] qapi: Add some union tests
Date: Tue, 31 Mar 2015 22:46:47 +0200	[thread overview]
Message-ID: <87ego43new.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <20150331171320.GD4748@noname.redhat.com> (Kevin Wolf's message of "Tue, 31 Mar 2015 19:13:20 +0200")

Kevin Wolf <kwolf@redhat.com> writes:

> Am 26.03.2015 um 16:04 hat Eric Blake geschrieben:
>> On 03/26/2015 07:18 AM, Markus Armbruster wrote:
>> > Eric Blake <eblake@redhat.com> writes:
>> >>                     Meanwhile, it would be nice to allow
>> >> 'discriminator':'EnumType' without 'base' for creating a simple union
>> >> that is type-safe rather than open-coded to a generated enum (right
>> >> now, we are only type-safe when using a flat union, but that uses
>> >> a different syntax of 'discriminator':'member-name' which requires
>> >> a base class containing a 'member-name' enum field).
>> > 
>> > I'm afraid I don't get you.  Can you give examples?
>> 
>> Using this common code with the appropriate union for each example:
>> { 'command':'foo', 'data':UNION }
>> 
>> Right now, we have flat unions which are required to be type-safe (all
>> branches MUST map back to the enum type of the discriminator, enforced
>> by the generator, so that if the enum later adds a member, the union
>> must also be updated to match):
>> 
>> [1]
>> { 'union':'Safe', 'base':'Base', 'discriminator':'switch',
>>   'data':{ 'one':'str', 'two':'int' }}
>> 
>> {"execute":"foo", "arguments":{'switch':'one', 'data':'hello'}}
>> 
>> and simple unions which cannot be typesafe (the branches of the union
>> are open-coded - even if they correlate to an existing enum, there is
>> nothing enforcing that extensions to the enum be reflected into the union):
>> 
>> [2]
>> { 'union':'SimpleButOpenCoded',
>>   'data':{ 'one': 'str', 'two':'int' }}
>> 
>> {"execute":"foo", "arguments":{'type':'one', 'data':'hello'}}
>> 
>> I'm hoping to add as a followup series a variant of simple unions that
>> is type-safe:
>> 
>> [3]
>> { 'union':'SimpleAndSafe', 'discriminator':'MyEnum',
>>   'data':{ 'one':'str', 'two':'int' }}
>> 
>> {"execute":"foo", "arguments":{'type':'one', 'data':'hello'}}
>
> This would overload 'discriminator' with two different meanings:
>
> * In case [1] it refers to one key in the JSON object which contains the
>   name of the union branch to select. That is, it is the _name_ of the
>   key used as a discriminator.
>
> * In case [3], the 'type' key is used in the JSON object to select a
>   union branch. 'discriminator' describes the _valid values_ of it, i.e.
>   the branch names.
>
> We shouldn't mix these meanings. If you need [3], we could call it
> 'discriminator-type' or something like that. If both options are
> consistently used for simple and flat unions, you end up with these
> rules:
>
> * 'discriminator' is the key that is used to select the union branch.
>
>   - For flat unions it is required and must refer to an explicitly
>     declared key in the base type.
>
>   - For simple unions it is optional and defaults to 'type'. The key is
>     implicitly created in the union type.
>
> * 'discrimiator-type' describes the valid values of 'discriminator',
>   either by referring to an enum type or to 'str'.
>
>   - For flat unions, this must match the type of the explicit
>     declaration of the discriminator field. It is optional and defauls
>     to the only valid value.
>
>   - For simple unions it is optional, too, and defaults to 'str'.
>
>   - If it is the name of an enum type, that enum type is reused and the
>     declared union branches must match the valid values of the enum.
>
>   - If it is 'str', a new enum is generated, and all the declared union
>     branches are used as valid values.
>
> There's quite some duplication in it where we need to make sure that the
> schema matches in all places, but without an explicit declaration of the
> disriminator field in simple unions, this seems to be the best I can
> come up with.
>
>> But the existing, unused-except-in-testsuite, notion of a simple union
>> with a base class looks like:
>> 
>> [4]
>> { 'type':'Shared', 'data':{'common':'int'}}
>> { 'union':'SimpleWithBase', 'base':'Shared',
>>   'data':{ 'one':'str', 'two':'int' }}
>> 
>> {"execute":"foo", "arguments":{'common':1, 'type':'one', 'data':'hello'}}
>> 
>> If we were to allow the addition of 'discriminator':'EnumType' to a
>> simple union [3], but then add that discriminator to an existing case of
>> a simple union with base [4], it would look like:
>> 
>> { 'type':'Shared', 'data':{'common':'int'}}
>> { 'union':'SimpleWithBaseAndDiscriminator', 'base':'Shared',
>>   'discriminator':'MyEnum',
>>   'data':{ 'one':'str', 'two':'int' }}
>> 
>> Yuck.  That is indistinguishable from flat unions [1], except by whether
>> discriminator names an enum type or a member of the base class.
>
> Which could even be ambiguous, couldn't it?
>
>> > In particular, I can define simple unions in terms of flat ones by
>> > restricting all union cases to a single member named 'data'.  They're
>> > not implemented that way, but that's a historical accident.  Simple
>> > unions are a redundant concept.
>> 
>> Cool.  Or more concretely,
>> 
>> { 'union': 'Simple', 'data': { 'one': 'str', 'two': 'int' } }
>> 
>> is identical on the wire to:
>> 
>> { 'enum': 'MyEnum', 'data': ['one', 'two'] }
>> { 'type': 'Base', 'data': { 'type': 'MyEnum' } }
>> { 'type': 'Branch1', 'data': { 'data': 'str' } }
>> { 'type': 'Branch2', 'data': { 'data': 'int' } }
>> { 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
>>   'data': { 'one': 'Branch1', 'two': 'Branch2' } }
>
> Perhaps we should expose all unions for schema introspection in a way
> similar to this (possibly not splitting out Branch1 and Branch2 as
> independent types, though).

My current thinking on this is a bit more radical.  I suspect there's a
straightforward object type buried in this mess, struggling to get out:
the good old variant record.  It consists of

* a name

* an optional base type name (must be a object type without variants)

* list of own members (empty okay)

  Effective members = own members + effective base type members

* optionally variants

  - one of the effective members is the discriminator (must be enum)

  - for each discriminator value a list of variant members (empty okay)

All existing type/union types are specializations:

* The complex type (struct type) is an object type without variants.

* The simple union type is an object type

  - without a base type

  - with an implicitly defined own member of an implicitly defined
    enumeration type serving as discriminator

  - with no other own members

  - with a single variant member for each discriminator value

* The flat union type is an object type

  - with a base type

  - without own members

  - with a discriminator

I further suspect lowering these types to the general form will make the
generator simpler, not just the introspection.

>                             We would just have to give a name to
> implicitly generated enums and base types.

Introspection doesn't care whether we defined something implicitly or
explicitly.  Let's make up names to hide that.

I'm trying to get a proof-of-concept introspection patch working this
week.  It'll probably be ugly enough to curdle the milk in your tea.

  parent reply	other threads:[~2015-03-31 20:46 UTC|newest]

Thread overview: 124+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-24 20:03 [Qemu-devel] [PATCH v5 00/28] drop qapi nested structs Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 01/28] qapi: Document type-safety considerations Eric Blake
2015-03-25 18:31   ` Markus Armbruster
2015-03-25 20:11     ` Eric Blake
2015-03-25 21:15       ` Eric Blake
2015-03-26  9:09         ` Markus Armbruster
2015-03-26  7:52       ` Markus Armbruster
2015-03-30 15:23         ` Eric Blake
2015-03-26  8:09       ` Markus Armbruster
2015-03-31 15:09   ` Kevin Wolf
2015-03-31 17:07     ` Eric Blake
2015-03-31 17:15       ` Kevin Wolf
2015-04-01 15:29   ` Markus Armbruster
2015-04-01 15:36     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 02/28] qapi: Fix generation of 'size' builtin type Eric Blake
2015-03-26  9:52   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 03/28] qapi: Require ASCII in schema Eric Blake
2015-03-24 20:33   ` Eric Blake
2015-03-26  9:54     ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 04/28] qapi: Add some enum tests Eric Blake
2015-03-26 10:01   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 05/28] qapi: Better error messages for bad enums Eric Blake
2015-03-26 10:08   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 06/28] qapi: Add some union tests Eric Blake
2015-03-26 13:18   ` Markus Armbruster
2015-03-26 15:04     ` Eric Blake
2015-03-27 12:30       ` Markus Armbruster
2015-03-27 19:47         ` Eric Blake
2015-03-31 17:13       ` Kevin Wolf
2015-03-31 18:15         ` Eric Blake
2015-03-31 18:31           ` Eric Blake
2015-03-31 18:34           ` Kevin Wolf
2015-03-31 20:46         ` Markus Armbruster [this message]
2015-04-01  8:23           ` Kevin Wolf
2015-04-01  9:14             ` Markus Armbruster
2015-03-26 13:23   ` Markus Armbruster
2015-03-26 13:51     ` Eric Blake
2015-03-26 15:58       ` Markus Armbruster
2015-03-30 22:45         ` Eric Blake
2015-03-31 23:40           ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 07/28] qapi: Simplify tests of simple unions Eric Blake
2015-03-26 13:41   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 08/28] qapi: Better error messages for bad unions Eric Blake
2015-03-24 20:38   ` Eric Blake
2015-03-26 14:20   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 09/28] qapi: Prepare for catching more semantic parse errors Eric Blake
2015-03-26 14:22   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 10/28] qapi: Segregate anonymous unions into alternates in generator Eric Blake
2015-03-26 14:47   ` Markus Armbruster
2015-03-26 15:26     ` Eric Blake
2015-03-27 12:32       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 11/28] qapi: Rename anonymous union type in test Eric Blake
2015-03-26 14:55   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 12/28] qapi: Introduce 'alternate' to replace anonymous union Eric Blake
2015-03-24 20:41   ` Eric Blake
2015-03-26 15:42   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 13/28] qapi: Add some expr tests Eric Blake
2015-03-26 15:55   ` Markus Armbruster
2015-03-26 19:02     ` Eric Blake
2015-03-27 12:38       ` Markus Armbruster
2015-03-27 19:39         ` Eric Blake
2015-03-29  8:27           ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 14/28] qapi: Better error messages for bad expressions Eric Blake
2015-03-26 16:27   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 15/28] qapi: Add tests of redefined expressions Eric Blake
2015-03-26 17:05   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 16/28] qapi: Better error messages for duplicated expressions Eric Blake
2015-03-26 17:21   ` Markus Armbruster
2015-03-27  7:52   ` Markus Armbruster
2015-03-27 19:53     ` Eric Blake
2015-03-29  8:38       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 17/28] qapi: Allow true, false and null in schema json Eric Blake
2015-03-26 17:32   ` Markus Armbruster
2015-03-31 15:23   ` Kevin Wolf
2015-03-31 20:09     ` Markus Armbruster
2015-04-01  8:31       ` Kevin Wolf
2015-04-01  9:33         ` Markus Armbruster
2015-04-01  9:58           ` Kevin Wolf
2015-04-01 11:03             ` Markus Armbruster
2015-04-01 11:17               ` Kevin Wolf
2015-04-01 14:51                 ` Markus Armbruster
2015-04-01 12:17           ` Eric Blake
2015-04-01 14:55             ` Markus Armbruster
2015-04-01 15:43             ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 18/28] qapi: Unify type bypass and add tests Eric Blake
2015-03-26 17:38   ` Markus Armbruster
2015-03-26 19:05     ` Eric Blake
2015-03-27 12:40       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 19/28] qapi: Add some type check tests Eric Blake
2015-03-26 17:58   ` Markus Armbruster
2015-03-26 19:07     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 20/28] qapi: More rigourous checking of types Eric Blake
2015-03-27  8:23   ` Markus Armbruster
2015-03-27 20:03     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 21/28] qapi: Require valid names Eric Blake
2015-03-27  8:48   ` Markus Armbruster
2015-03-27 20:15     ` Eric Blake
2015-03-29 10:17       ` Markus Armbruster
2015-03-29 14:23         ` Markus Armbruster
2015-03-27 17:14   ` Markus Armbruster
2015-03-27 20:17     ` Eric Blake
2015-03-29  9:06   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 22/28] qapi: Whitelist commands that don't return dictionary Eric Blake
2015-03-27  9:11   ` Markus Armbruster
2015-03-27 20:20     ` Eric Blake
2015-03-27 16:19   ` Markus Armbruster
2015-03-27 20:29     ` Eric Blake
2015-03-29 10:22       ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 23/28] qapi: More rigorous checking for type safety bypass Eric Blake
2015-03-27  9:45   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 24/28] qapi: Merge UserDefTwo and UserDefNested in tests Eric Blake
2015-03-27  9:52   ` Markus Armbruster
2015-03-27 20:30     ` Eric Blake
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 25/28] qapi: Drop tests for inline nested structs Eric Blake
2015-03-27 10:30   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 26/28] qapi: Drop inline nested type in query-version Eric Blake
2015-03-27 10:34   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 27/28] qapi: Drop inline nested types in query-pci Eric Blake
2015-03-27 10:37   ` Markus Armbruster
2015-03-24 20:03 ` [Qemu-devel] [PATCH v5 28/28] qapi: Drop support for inline nested types Eric Blake
2015-03-27 10:45   ` Markus Armbruster
2015-03-27 12:50 ` [Qemu-devel] [PATCH v5 00/28] drop qapi nested structs Markus Armbruster
2015-03-29 16:03 ` Markus Armbruster
2015-03-31  4:30   ` Eric Blake

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ego43new.fsf@blackfin.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=famz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=wenchaoqemu@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.