And notice also that while the Turbo module implements a code generated spec, its internal implementation and the way that it calls into the C bridge, it is type safe, but it could be using and calling incorrectly, which is also another potential issue. And this is because calling from Rust libraries into C++ and with these and the other way around, it quickly becomes very complicated and error prone, especially for complex data types, like structs and things with objects with lifetimes, references to objects with lifetimes. And it's often repetitive, verbose. There's a lot of good reasons why we like to write code in a higher level language. And it often leads to memory leaks and runtime crashes because memory management like doing that manually and also object lifetime aware code, it's very hard to write in a good way. I think it's basically, it's like an endless point of frustration and pain and potentially it will be illegal in the future as well. So it's not a lot of fun to debug these things, to write them or debug them. And here's my heartache, if C is ever a part of your project, it should be generated and considered ephemeral, some sort of like intermediary representation. And there should be no need to commit this into your repository if at all can be avoided.
So what are the alternatives to this? So the first alternative I want to mention is UniFFI by Mozilla. You can use this to alleviate the pain or at least some of the pain. It features multiple target languages. So React Native being one of them. And it is optimized for a broad support of target platforms and it uses a lot of martialing and copying of data to achieve that. It favors ease of implementation and understanding over performance as they write on their own documentation. And this might be the right trade off for you. As I was building a proof of concept for a UniFFI binding for the auto-merge trade back in December, I noticed the rush code I needed to write there to basically prepare it for being exposed this way was considerably, it was the most, there was a lot of code that I needed to write to expose it in a reliable way.
Another alternative is SaferFFI by Dido, and it is improving the developer experience of maintaining such a foreign function interface or ZBridge. It is used and maintained by Dido, as I said, in this local first peer-to-peer sync solution. And it helps deduce safe blocks, sorry, it helps reduce the unsafe blocks in your rush code and it generates a C header for the consumer, but the consuming side of the bridge you still need to implement and maintain manually. And in the context of ABI stability and React Native, you might have also heard about the Hermes ABI. It's an experimental C-based stable ABI for Hermes. So on the surface, exactly what we need, but it's not really for general consumption. And in their own words, it doesn't immediately solve the ABI stability for native libraries targeting React Native. So not React Native itself, but the libraries that built on top of it. And this is because the libraries will still consume a C++ JSI runtime pointer provided by React Native and not Hermes. And the Hermes team is aware of this, and it's within the scope of their efforts to solve this eventually. Until it's ready, I do think that we have other and more, in my opinion, better alternatives available. So this thing happened at React Summit US last year. In the end of the year, I was presenting a talk on building C++ JSI native modules for React Native.
Comments