All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Het Gala <het.gala@nutanix.com>
Cc: "Daniel P. Berrangé" <berrange@redhat.com>,
	qemu-devel@nongnu.org, prerna.saxena@nutanix.com,
	quintela@redhat.com, dgilbert@redhat.com, pbonzini@redhat.com,
	eblake@redhat.com, manish.mishra@nutanix.com,
	aravind.retnakaran@nutanix.com
Subject: Re: QAPI unions as branches / unifying struct and union types
Date: Tue, 14 Feb 2023 11:16:28 +0100	[thread overview]
Message-ID: <87v8k4lfgj.fsf@pond.sub.org> (raw)
In-Reply-To: <2157ed5c-7e1e-bd8f-1644-b7231fffe7ef@nutanix.com> (Het Gala's message of "Fri, 10 Feb 2023 18:58:32 +0530")

Het Gala <het.gala@nutanix.com> writes:

> On 10/02/23 12:54 pm, Markus Armbruster wrote:
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>>
>> [...]
>>
>>>> +##
>>>> +# @MigrateAddress:
>>>> +#
>>>> +# The options available for communication transport mechanisms for migration
>>>> +#
>>>> +# Since 8.0
>>>> +##
>>>> +{ 'union' : 'MigrateAddress',
>>>> +  'base' : { 'transport' : 'MigrateTransport'},
>>>> +  'discriminator' : 'transport',
>>>> +  'data' : {
>>>> +    'socket' : 'MigrateSocketAddr',
>>>> +    'exec' : 'MigrateExecAddr',
>>>> +    'rdma': 'MigrateRdmaAddr' } }
>>>
>>> Ideally this would be
>>>
>>>     'data' : {
>>>       'socket' : 'SocketAddress',
>>>       'exec' : 'MigrateCommand',
>>>       'rdma': 'InetSocketAddress' } }
>>>
>>> though the first SocketAddress isn't possible unless it is easy to
>>> lift the QAPI limitation.
>>
>> Context: SocketAddress is a QAPI union, and "the QAPI limitation" is
>>
>>      scripts/qapi-gen.py: In file included from ../qapi/qapi-schema.json:79:
>>      ../qapi/migration.json: In union 'MigrateAddress':
>>      ../qapi/migration.json:1505: branch 'socket' cannot use union type 'SocketAddress'
>>
>> Emitted by schema.py like this:
>>
>>                  if (not isinstance(v.type, QAPISchemaObjectType)
>>                          or v.type.variants):
>>                      raise QAPISemError(
>>                          self.info,
>>                          "%s cannot use %s"
>>                          % (v.describe(self.info), v.type.describe()))
>>
>> This enforces docs/devel/qapi-code-gen.rst's clause
>>
>>      The BRANCH's value defines the branch's properties, in particular its
>>      type.  The type must a struct type.  [...]
>>
>> Next paragraph:
>>
>>      In the Client JSON Protocol, a union is represented by an object with
>>      the common members (from the base type) and the selected branch's
>>      members.  The two sets of member names must be disjoint.
>>
>> So, we're splicing in the members of the branch's JSON object.  For that
>> to even make sense, the branch type needs to map to a JSON object.  This
>> is fundamental.  It's the first part of the condition in the code
>> snippet above.
>>
>> We have two kinds of QAPI types that map to a JSON object: struct and
>> union.  The second part of the condition restricts to struct.  Unless
>> I'm missing something (imperfect memory...), this is *not* fundamental,
>> just a matter of implementing it.  But I'd have to try to be sure.
>>
>>
>> Instead of simply allowing unions in addition to structs here, I'd like
>> to go one step further, and fuse the two into "objects".  Let me
>> explain.
>>
>> If we abstract from syntax, structs have become almost a special kind of
>> union.  Unions have a set of common members and sets of variant members,
>> and a special common member (the tag) selects the set of variant
>> members.  Structs are unions with zero variants and no tag.
>>
>> The generator code actually represents both structs and unions as a
>> common QAPISchemaObjectType already.  QAPI/QMP introspection does the
>> same: it uses a single meta type 'object' for both.
>>
>>
>> There is another spot where only structs are allowed: a struct or
>> union's base type.  That restriction will be awkward to lift, as I made
>> the mistake of baking the assumption "object type has at most one tag
>> member" into QAPI/QMP introspection .
>
> Hi Markus, thankyou for explaning in such detail. I tried to understand of what you explained.
>
> So IIUC, you mentioned the QAPI generator treats both structs and unions same, but basically in the schema.py checks is where it tries to distinguish between the two ? and because of the fact that docs/devel/qapi-code-gen.rst states that for a union, it's branches must be 'struct', and that's the reason it gives an error ?

Permit me a brief digression into history.

The initial QAPI design language provided product types (structs) and
sum types (unions containing exactly one of several types, and a tag
member that tells which one).  The two are orthogonal.

These unions turned out rather awkward.

The unions we have today are more general.  They have common members,
and one of them is the tag member, of enumeration type.  For each tag
value, they have variant members.  Both the common members and each tag
value's variant members are given as struct types.

What if the tag's enumeration type is empty, i.e. has no values?  We get
a union with no variant members, only common ones.  Isn't that a struct?

Not quite.  To get a struct, we also have to drop the tag member.  It
has no possible values anyway.

You see, struct types are almost a special case of today's union types.
To overcome "almost", we can introduce the notion of "object type":

* An object type has common members, one of them can be a tag member, of
  enumeration type, not empty.  For each tag value, it additionally has
  variant members.

* A union type is an object type with a tag member and variant members.

* A struct type is an object type without tag member and variant
  members.

The QAPI generator code already made the jump to this object type
notion.  It transform the special cases into the general case at first
opportunity, in QAPISchema._def_struct_type() and ._def_union_type().

*Except* we haven't implemented support for variant members in a few
places where they cannot occur now, e.g. as a tag value's variant.  This
is the restriction you ran into.

I'd like to make the jump to object type in the QAPI schema language,
too.  But that's not a prerequisite to lifting the restriction.

> If that's the case, can we improve on our checks and allow union as a part of branch of a union ? or something else ?

I believe we can implement the missing parts and relax the checks.  But
to be sure, we need to try.

> or I may have completely misunderstood most of the part 😅. Please let me know

More questions?



  reply	other threads:[~2023-02-14 10:17 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-08  9:35 [PATCH v2 0/6] migration: Modified 'migrate' QAPI command for migration Het Gala
2023-02-08  9:35 ` [PATCH v2 1/6] migration: moved hmp_split_at_commma() helper func to qapi-util.c file Het Gala
2023-02-09 12:00   ` Markus Armbruster
2023-02-09 12:12     ` Juan Quintela
2023-02-09 13:58       ` Het Gala
2023-02-09 16:19       ` Markus Armbruster
2023-02-09 13:28     ` Het Gala
2023-02-09 12:02   ` Daniel P. Berrangé
2023-02-09 13:30     ` Het Gala
2023-02-08  9:35 ` [PATCH v2 2/6] migration: Updated QAPI format for 'migrate' qemu monitor command Het Gala
2023-02-08 20:17   ` Eric Blake
2023-02-09  7:57     ` Het Gala
2023-02-09 10:23     ` Daniel P. Berrangé
2023-02-09 13:00       ` Het Gala
2023-02-09 13:38       ` Daniel P. Berrangé
2023-02-10  6:37         ` Het Gala
2023-02-10 10:31         ` Markus Armbruster
2023-02-09 16:26       ` Markus Armbruster
2023-02-10  6:15         ` Het Gala
2023-02-09 10:29   ` Daniel P. Berrangé
2023-02-09 13:11     ` Het Gala
2023-02-09 13:22       ` Daniel P. Berrangé
2023-02-10  8:24         ` Het Gala
2023-02-10  7:24     ` QAPI unions as branches / unifying struct and union types (was: [PATCH v2 2/6] migration: Updated QAPI format for 'migrate' qemu monitor command) Markus Armbruster
2023-02-10 13:28       ` Het Gala
2023-02-14 10:16         ` Markus Armbruster [this message]
2023-02-17 11:18           ` QAPI unions as branches / unifying struct and union types Het Gala
2023-02-17 11:55             ` Daniel P. Berrangé
2023-02-21  9:17               ` Het Gala
2023-02-08  9:35 ` [PATCH v2 3/6] migration: HMP side changes for modified 'migrate' QAPI design Het Gala
2023-02-09 12:05   ` Daniel P. Berrangé
2023-02-09 13:38     ` Het Gala
2023-02-09 14:00       ` Daniel P. Berrangé
2023-02-10  6:44         ` Het Gala
2023-02-08  9:35 ` [PATCH v2 4/6] migration: Avoid multiple parsing of uri in migration code flow Het Gala
2023-02-09 10:40   ` Daniel P. Berrangé
2023-02-09 13:21     ` Het Gala
2023-02-09 12:09   ` Daniel P. Berrangé
2023-02-09 13:54     ` Het Gala
2023-02-09 14:06       ` Daniel P. Berrangé
2023-02-10  7:03         ` Het Gala
2023-02-08  9:35 ` [PATCH v2 5/6] migration: Modified 'migrate-incoming' QAPI and HMP side changes on the destination interface Het Gala
2023-02-08 20:19   ` Eric Blake
2023-02-09  7:59     ` Het Gala
2023-02-09 10:31   ` Daniel P. Berrangé
2023-02-09 13:14     ` Het Gala
2023-02-09 13:25       ` Daniel P. Berrangé
2023-02-08  9:36 ` [PATCH v2 6/6] migration: Established connection for listener sockets on the dest interface Het Gala

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=87v8k4lfgj.fsf@pond.sub.org \
    --to=armbru@redhat.com \
    --cc=aravind.retnakaran@nutanix.com \
    --cc=berrange@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=eblake@redhat.com \
    --cc=het.gala@nutanix.com \
    --cc=manish.mishra@nutanix.com \
    --cc=pbonzini@redhat.com \
    --cc=prerna.saxena@nutanix.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.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.