How best to do async functions and XPCOM?
Hi all I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd like to use Promises but a lot of the time I'll be far from a JS context so that doesn't really seem like an option. The best alternative I've come up with is to create some sort of listener object and pass it to the async function: interface nsIFooOperationListener : nsISupports { void onOperationComplete( in nsresult status, [optional] in string errorMessage ); }; ... void fooFunction(..., in nsIFooOperationListener listener); This works fine but I wonder if there's a better way, or if there's some established prior art I can use/borrow rather than find out the pitfalls myself. TIA, GL ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On Friday, December 6, 2019 at 9:20:21 AM UTC+11, Geoff Lankow wrote: > Hi all > > I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd > like to use Promises but a lot of the time I'll be far from a JS context > so that doesn't really seem like an option. The best alternative I've > come up with is to create some sort of listener object and pass it to > the async function: > > interface nsIFooOperationListener : nsISupports { >void onOperationComplete( > in nsresult status, > [optional] in string errorMessage >); > }; > > ... > > void fooFunction(..., in nsIFooOperationListener listener); > > This works fine but I wonder if there's a better way, or if there's some > established prior art I can use/borrow rather than find out the pitfalls > myself. > > TIA, > GL We have mozilla::MozPromise [0], similar to mozilla::dom::Promise but it doesn't rely on JS at all. It can be a bit tricky to use, the simplest way (to start) is probably to do something like InvokeAsync(work thread, code to run that resolves or rejects the promise)->Then(target thread, on-success follow-up, on-failure follow-up) (e.g., [1]). Good luck! g. [0] https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/xpcom/threads/MozPromise.h#98 [1] https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/dom/media/ChannelMediaDecoder.cpp#392 ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On 12/5/19 5:20 PM, Geoff Lankow wrote: I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd like to use Promises but a lot of the time I'll be far from a JS context Is that because both the implementation of the API and the consumer of the API will be C++? For what it's worth, you are never far from a JSContext; AutoJSAPI will give you one. The hard part may be finding an appropriate global to use... In general, if the consumer or implementor of the API is JS, I would use JS promises. If this is all in C++ land, MozPromise works fine, afaict. -Boris ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On Friday, December 6, 2019 at 7:20:21 AM UTC+9, Geoff Lankow wrote: > Hi all > > I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd > like to use Promises but a lot of the time I'll be far from a JS context > so that doesn't really seem like an option. The best alternative I've > come up with is to create some sort of listener object and pass it to > the async function: > > interface nsIFooOperationListener : nsISupports { >void onOperationComplete( > in nsresult status, > [optional] in string errorMessage >); > }; > > ... > > void fooFunction(..., in nsIFooOperationListener listener); > > This works fine but I wonder if there's a better way, or if there's some > established prior art I can use/borrow rather than find out the pitfalls > myself. > > TIA, > GL I recently got a chance to play with MozPromise [0] in a pure C++ function to access Windows API. It served my purpose well except that I had to use a bit hacky way to pass `MozPromiseHolder` into a lambda expression. [0]: https://phabricator.services.mozilla.com/D42484 ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On 12/5/2019 6:33 PM, Gerald Squelart wrote: On Friday, December 6, 2019 at 9:20:21 AM UTC+11, Geoff Lankow wrote: Hi all I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd like to use Promises but a lot of the time I'll be far from a JS context so that doesn't really seem like an option. The best alternative I've come up with is to create some sort of listener object and pass it to the async function: interface nsIFooOperationListener : nsISupports { void onOperationComplete( in nsresult status, [optional] in string errorMessage ); }; ... void fooFunction(..., in nsIFooOperationListener listener); This works fine but I wonder if there's a better way, or if there's some established prior art I can use/borrow rather than find out the pitfalls myself. TIA, GL We have mozilla::MozPromise [0], similar to mozilla::dom::Promise but it doesn't rely on JS at all. It can be a bit tricky to use, the simplest way (to start) is probably to do something like InvokeAsync(work thread, code to run that resolves or rejects the promise)->Then(target thread, on-success follow-up, on-failure follow-up) (e.g., [1]). The problem with MozPromise is that it doesn't integrate well if you use XPIDL interfaces, so you have this annoying issue that if you want to use XPIDL integration, you have to use mozilla::dom::Promise, which is annoying to use from C++. A third wrinkle, especially now that async functions has landed in Rust, is if you want to try to use std::future::Future in Rust, which isn't going to convert terribly well to either form. It may be worth spending some time building some wrappers to integrate between all of our various async function frameworks... -- Joshua Cranmer Thunderbird and DXR developer Source code archæologist ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On Fri, Dec 06, 2019 at 11:20:12AM +1300, Geoff Lankow wrote: Hi all I'm redesigning a bunch of Thunderbird things to be asynchronous. I'd like to use Promises but a lot of the time I'll be far from a JS context so that doesn't really seem like an option. The best alternative I've come up with is to create some sort of listener object and pass it to the async function: interface nsIFooOperationListener : nsISupports { void onOperationComplete( in nsresult status, [optional] in string errorMessage ); }; ... void fooFunction(..., in nsIFooOperationListener listener); This works fine but I wonder if there's a better way, or if there's some established prior art I can use/borrow rather than find out the pitfalls myself. In general, if you're thinking about using an XPIDL interface for something, you're probably going down the wrong track. If you're only going to be dealing with C++, then you should generally use a pure C++ interface (probably just MozPromise in this case). If you're going to need to interact with JS at any point, you should probably just use dom::Promise. You can always use AutoJSAPI to get a JSContext, and create the Promise in the shared JSM global. ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On Sun, Dec 08, 2019 at 11:40:52PM -0500, Joshua Cranmer 🐧 wrote: The problem with MozPromise is that it doesn't integrate well if you use XPIDL interfaces, so you have this annoying issue that if you want to use XPIDL integration, you have to use mozilla::dom::Promise, which is annoying to use from C++. In what way is dom::Promise annoying to use from C++? The entire purpose of dom::Promise is to make JS promises easy to use from C++. ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
Also sprach Joshua Cranmer: > The problem with MozPromise is that it doesn't integrate well if you use > XPIDL interfaces, so you have this annoying issue that if you want to use > XPIDL integration, you have to use mozilla::dom::Promise, which is annoying > to use from C++. A third wrinkle, especially now that async functions has > landed in Rust, is if you want to try to use std::future::Future in Rust, > which isn't going to convert terribly well to either form. In this context it should also be mentioned that the Rust XPCOM bindings do not support DOM promises quite yet: https://bugzilla.mozilla.org/show_bug.cgi?id=1512319 ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
Thanks to all who replied, including Kris whose reply seems to have not made it back to the list. As per usual when I ask for help I've been immediately distracted by something more urgent and not got back to the problem at hand. :-/ As some pointed out this would be a lot easier if I was exclusively in JS-land or in C++-land, but I'm not. Nor am I starting something new from scratch, which also be easier. I'm modernising some existing components while trying to avoid wholesale rewriting of major parts of the program. There are multiple pieces in both languages and they all interact. Also some of this code is *really* old in Mozilla terms, which is, um, helpful… GL ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On 12/10/19 3:31 PM, Kris Maglione wrote: In what way is dom::Promise annoying to use from C++? The one thing I know about that's pretty annoying is if you receive the promise from someone else and want to add reactions to it. PromiseNativeHandler kinda works, but then you get JS::Values and have to extract the things you care about from them manually, which is a bit of a pain. -Boris ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform
Re: How best to do async functions and XPCOM?
On Thu, Dec 12, 2019 at 09:30:06AM -0500, Boris Zbarsky wrote: On 12/10/19 3:31 PM, Kris Maglione wrote: In what way is dom::Promise annoying to use from C++? The one thing I know about that's pretty annoying is if you receive the promise from someone else and want to add reactions to it. PromiseNativeHandler kinda works, but then you get JS::Values and have to extract the things you care about from them manually, which is a bit of a pain. Note that you can also use `ThenWithCycleCollectedArgs` and `ThenWithoutCycleCollection` to add reactions from native code, which is a lot easier than `PromiseNativeHandler`. You do still need to manually deal with JS::Values, though. ___ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform