JavaScript components should avoid nsIPropertyBag like the plague

I’ve been bitten by this a dozen times over the years. I try to find a simple data interface for getting a bunch of strings out, and I see nsIPropertyBag. I think to myself, “Hmm. That’s a pretty good choice.” Then I implement it, watch it QueryInterface for my component, and then watch it not call my getProperty() method. Why? XPConnect returns its own nsIPropertyBag object first when I try to call getProperty(). So my call goes to a different object than the one I intended.

I never, ever learn.

Arrays of strings in XPCOM

In my XPCOM Cheat Sheet (which I really should look at updating), I wrote:

As a rule of thumb, use XPIDL-based arrays for arrays of a single
primitive type, in or out (not inout). For anything else, use nsIArray or
nsIMutableArray.

Unfortunately, that doesn’t work with native string types like DOMString:

interface nsIFooArray : nsISupports
{
void setArray(in PRUint32 count,
[array, size_is(count)]
in DOMString strings);
};
Error: [domstring], [utf8string], [cstring], [astring] types cannot be used in array parameters

To which I say, “Well, that sucks.” Read on in the extended entry for more details.

Continue reading Arrays of strings in XPCOM

Back to Basics: Two-Dimensional Arrays

I had planned to write an article on ECMAScript Harmony and my ideas for corresponding XPIDL changes… but four months after its announcement, I find I still don’t know what’s in the Harmony spec! (We know a few things that are out… but since the initial blog surge, it’s been quiet.)

So I’ve decided to put my ideas for XPIDL on the side, and move on to the last part in this series: my attempt at creating a XPCOM component for two-dimensional arrays. Read on for further details.

Continue reading Back to Basics: Two-Dimensional Arrays

Back to Basics: Why write components in C++?

A year or so ago, I introduced the ArrayConverter
module
to Verbosio, and tried to get it into mozilla.org code. The idea
was simple: a JavaScript library for converting between native JavaScript
arrays, XPCOM arrays, nsIArray objects and nsISimpleEnumerator
objects. Although it did not get in, I’ve been rethinking half of the
ArrayConverter module’s functionality, and I believe now that I
overlooked something.

I planned on writing two different articles – one talking about
reinventing the wheel unnecessarily, and another talking about why I, a
JavaScript expert, would choose to write XPCOM components in C++. It turns
out, though, that each of these has roughly the same answer: the penalties of
XPConnect. Read on for
further details.

Continue reading Back to Basics: Why write components in C++?

Back to Basics: Read-only Data

(I’m posting two articles today – and for those of you who correctly pointed out my XPCOM Services article had bugs in the sample code, I’ve updated it to point to live code with a couple adjustments. I continue to welcome your insight.)

XPCOM provides a lot of basic data types – nsIVariant
is one of the more complex ones from a C++ standpoint. In particular, they
provide arrays through the nsIArray
interface, object containers through nsIPropertyBag
and nsIPropertyBag2,
and a bunch of primitive values such as strings and floating-point numbers
through nsISupportsPrimitives.
XPCOM also provides components
and contracts
for these data types in C++, so you don’t have to
reimplement them. (You can if you want to, but it’s usually not necessary, as
I’ll explain in another article.)

There’s only one downside to these basic components: they’re eternally
changeable. What that means is I can pass a
nsISupportsString to your component, and it can change that
value before sending it onto another component. From my perspective, I don’t
have any way of “sealing” the data, of making it read-only. Even if I pass
you one of these components in an interface that has no change methods
(nsIArray), you could easily QueryInterface it for
an interface that has change methods (nsIMutableArray).
You’ll find an exception to the rule in nsIWritableVariant, but
that’s about it.

In this article, I’ll talk about two approaches to this problem – and the
choice I made.

Continue reading Back to Basics: Read-only Data

Finding files missing a tri-license?

Dear Lazyweb,

I realized that for Verbosio, I have forgotten to explicitly add the MPL/GPL/LGPL tri-license boilerplate to a number of my files. Although the project is open-source and under these licenses, I still see the missing boilerplates as an oversight.

I did a quick Google search for Perl scripts to find these files, and found only this: an Add_License script. It does support MPL, but not the tri-license.

Does anyone out there have a script for identifying these files? I’d prefer to add the boilerplates myself, but I still need to search for where they are not.

Back to Basics: Defining XPCOM Services

Once upon a time, I asked a question in the #developers channel
on irc.mozilla.org:

How do I define that a XPCOM component is
actually a service?

The answer I received:

See if the caller uses do_GetService(), or
Components.classes[…].getService().

This is less than satisfactory. I should be able to say “There can be only
one” and not “Oh, please, don’t create more than one of me.” Over the years,
I came up with different solutions for JavaScript – and I recently discovered
the standard way to do it for C++-based XPCOM components. Read on in the
extended entry for details.

Continue reading Back to Basics: Defining XPCOM Services

Back to Basics: Judo with nsIVariant

With XPIDL, XPCOM components can be very strict about what they allow.
Simply put, if you try to pass in an argument to a XPCOM component, and the
component requires a type that your argument doesn’t support, it won’t work.
In C++, your program won’t compile; in JavaScript, XPConnect throws
exceptions. This is a good thing.

Many of the basic data structures – nsIArray, nsIPropertyBag, etc. – take
a nsISupports argument. This covers most objects you construct
and work with. This is all well and good… unless you want to pass in a raw
type such as a number, a true or false value, a
string, etc. Then you’re stuck.

Fortunately, all is not lost. There is an interface named
nsIWritableVariant, which XPCOM provides for wrapping native
types in an nsISupports object. (There are type-specific
interfaces like nsISupportsPRBool as well, but
nsIWritableVariant is an one-size-fits-all solution.) Even more
interesting, its read-only companion, nsIVariant, is “magical”
to XPConnect: JavaScript receives its values as native types, not as
nsIVariant objects.

Thus, nsIVariant turns the strengths of XPIDL barriers so
that they are no longer fighting you, but working with you. This is what I am
calling judo with nsIVariant. Read on in the extended entry for more details.

Continue reading Back to Basics: Judo with nsIVariant

Back to Basics: XPCOM Arrays and Memory

A couple weeks ago, I started reading “Learning Python”, by
Mark Lutz. It’s an interesting feeling, going back to the basics of
programming – numbers, strings, arrays, etc. In reading this book, I kept
thinking there were some things missing from the basic XPCOM tool set.
Therefore, I decided to attempt implementing these missing pieces.

Now, I could be totally wrong about any or all of these being missing…
but it’s also a good exercise for me to push my boundaries and strengthen my
C++ skill set. The result is not only code that I can use for
proof-of-concept, but code that may be useful elsewhere.

This is the first article in a multipart series titled “Back to Basics”,
exploring these concepts. This first article is about native C++ arrays
through XPCOM – and making sure I don’t leak memory. Read on in the extended
entry for details.

Continue reading Back to Basics: XPCOM Arrays and Memory

Alex Vincent’s ramblings about Mozilla technology, authoring, and whatever he feels like.