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