The last few months I’ve tried submitting patches to Mozilla implementing some feature as a XPCOM component, I’ve been told XPCOM’s the wrong way to go. I don’t understand why, though.
A lot of my work – especially Verbosio – has been based on the idea that JS components work. I can clearly define the interfaces in XPIDL, with some type checking done for me by XPConnect. Ditto for scriptable C++-based components, which I write only when I feel I have to.
I’d really like someone to write a DevMo or WikiMo article (or failing that, a blog post), explaining best practices, the costs of XPCOM, and alternatives. There’s several areas to cover:
- C++ to C++
- C++ code called from JS
- JS code called from C++
- JS to JS
- Privileged code called from content (not escalating content to privileges, just code that runs with privileges but exposed through some public interfaces to content)
- Anything obvious that I’ve missed.
Many of my own blog entries have been all about leveraging XPCOM. Having it explained in a tech note could profoundly affect the way I do things.
(I know I sound like a jerk in this article, and the tone is a bit hostile. I apologize for that, but as usual, I’m having trouble editing my own words… I can write new words, but which ones?)
P.S. Thanks for all the replies to my previous post… very informative, very useful opinions!
7 thoughts on “Why is it so wrong to write XPCOM components?”
I am using JS components in BlueGriffon to provide app-level public APIs to add-on authors and kernel hacker. It’s clearly the best way to do that and I don’t want to be back to saying authors please include this chrome script into your XUL page.
I finally took the plunge and started moving my XPCOM Components to JS Modules and was surprised at how well it worked (and I was addicted to XPCOM Components)
I was primarily using them to have one instance of things across multiple windows and that can now be done with JS Modules.
I’m sure I’ll run into things that can only be accomplished with a component (adding a protocol handler comes to mind), but so far I’ve been surprised that I’ve been able to move just about everything to JS Modules.
In general, XPCOM APIs can be difficult to use for people who are not familiar with COM or XPCOM. However, JS modules let you write an API in JS, which can often be far more expressive.
While I don’t know what APIs you’ve tried to implement, I suspect you were told you should use a JS module instead. The reason why is because we are trying to make the platform more approachable, and XPCOM is not terribly approachable.
I’ve also been addicted to JS XPCOM, but just like Michael I am now converting everything to JS modules.
Though there where multiple reasons for using XPCOM back then (and drawbacks from my current point of view).
1. Having clean interfaces
– Well, IDL is nice, but it is also a lot of work to manage (using xpidl, keeping the IDL and the JS members in sync, etc.). And coming with Gecko 2, registration of XPCOM components will change.
2. I thought, I may want to convert some of my JS components to C++ – using XPCOM this would pretty easy as I wouldn’t need to change any other code apart from the component itself.
– In the end, I didn’t rewrite any component in C++. Spidermonkey is getting faster and faster each day, so performance isn’t a big problem these days. Though, if I really need something to be really fast, I can still use js-ctypes or write a XPCOM component in C++. Also, pure JS is more performant than JS XPCOM as the XPConnect overhead is reduced.
Getting rid of XPCOM gave me some more advantages:
1. No more XPCOM-bloat in the classes / components, no more XPCOM-syntax (though Components.Constructor at least already removed some of that), no more QueryInterface
2. Finally my constructors can have parameters (though this is also possible with Components.Constructor)
3. Inheritance (kind of possible with JS XPCOM, but I actually didn’t trust my own way of doing it)
All in all, my code is now easier to maintain. I really wouldn’t use XPCOM in cases where it isn’t really needed.
Hope this helps.
p.s. Besides, I trust JS garbage-collection more than XPCOM memory management.
Firebug move all of its XPCOM components into Mozilla ‘modules’ (now 8 total). We saw no downside and the code is clearer now. Plus this was a good intermediate step towards RequireJS style modules.
Chromebug has two remaining components, one command line handler and one profile-after-start handler. These are examples of when components are essential.
What sort of feature(s)? Any Bug numbers? Perhaps we could use them in SeaMonkey.
There are a number of reasons, most of which have already been mentioned in the comments.
1) Implementing interfaces as defined in IDL gives you both a crappy C++ interface and a crappy JS interface. Our new school of thought is: if you only need it in JS, implement a JS module. If you need it in C++ and JS, implement the C++ interface you want, then use JSAPI or js-ctypes to implement a nice JS interface in a JS module
2) XPCOM+xpconnect has a lot of overhead, which is even more noticeable on mobile.
3) We have better solutions in the platform for most of the things you list. js-ctypes for calling C code from JS, JS modules for calling JS from JS.
4) Most of the proposed benefits of XPCOM are either not used in practice, or turn out to be bad ideas if actually used. For example, you can override most contract IDs, but we have lots of code that assumes that there’s only one true implementation. Plus, we pay a performance penalty in calling virtual methods for core services that should only ever have one implementation. Finally, allowing random services to be implemented in script, while a neat idea, leads to bugs (including security bugs) by having script on the stack where code isn’t expecting it to be.
Comments are closed.