RFC: IPDL discriminated union types

Chris Jones <[email protected]>
Newsgroups gmane.comp.mozilla.devel.dom
Message-ID <[email protected]>
NPAPI contains functions that accept NPVariant types.  NPVariant is 
defined in NPAPI as an old-school |struct { enum; union; }|.  For IPDL, 
NPVariant is problematic because NPVariant may contain a "basic" C++ 
type (like bool, int, ...) or an IPDL type (NPObject).  If an NPVariant 
value represents an IPDL type, IPDL needs to know about it because 
special serialization is used for those types.  Generally, it's 
problematic to "hide" an IPDL type in an opaque C++ union {}, because 
IPDL won't know how to serialize the union correctly.

One way to handle this problem is for IPDL to expose the representation 
of IPDL types in terms of "basic types" (int, ...).  This would allow 
C++ code to serialize IPDL types buried in unions.

But I think we can do better.  I propose adding "discriminated union" 
types to IPDL, so that unions aren't opaque to IPDL  (this follows a 
recommendation from Brendan Eich).  Discriminated unions would be 
declared with the following syntax

   union Foo {
     int;
     bool;
     NPObject;
     //...
   }

(This syntax is intended to be faithful to C++.  What's really meant by 
this is something closer to the ML |type Foo = Tint of int | Tbool of 
bool; ...|.)

This declaration will pass down to C++ in the following way (I hope it's 
clean!).  The |Foo| union C++ definition will be generated into the IPDL 
header for whatever protocol its included in.  Programmers never need to 
set the C++ Foo type; it can be done by the C++ compiler.  For example:

   int i = 42;
   Foo f = i;

will set the type of |f| to Tint, and assign the value of |i| to |f|. 
The most painful part of dealing with these unions will be "unpacking" 
the value; that is, after sending Foo from one process to another, 
switching on its actual type.  Because we're working in C++ and not ML, 
this won't be ideal.  It'll look like

   // IPDL message handler that receives |Foo f|

   switch (f.type()) {
   case Tint: {
      int i = f;
      // do something with i
   }

   case Tbool: {
      bool b = f;
      // do something with b
   }

   case TNPObject: {
      NPObject* o = f;
      // do something with o
   }
   }

I wrote some proof-of-concept C++ code last night, so I know that this 
can be done.

Comments?

Cheers,
Chris
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.