Meta-typesystem best practices #1198
Replies: 1 comment 1 reply
-
Thanks for the question, yes I think in general meta object level communication could probably be improved. There are a few steps to get there that might help a bit. We are about to land up/down casting of types on the Rust side #1159 this would then allow you to get from your MyObject* to a QObject* easily or from a QObject* to a MyObject*. Once we have landed this it would make sense to start adding some more bindings for more of the fundamental types such as QObject and QQuickItem. It is unfortunate that Qt uses raw pointers instead of shared/unique pointers as this means when you are using most QtWidgets APIs or passing around pointers to other QML elements you need to deal with raw pointers on the Rust side and convert them to a pinned mutable which then leads to small unsafe block. I'm not sure there is any way around this with what is available in std, but maybe we could provide a safe conversion helper. However note that once #1159 lands there are methods such as Templates / generics in CXX are unfortunately verbose currently, but at least you can define each concrete implementation and it works. As for your problem, once we support casting it could then start to make sense for us to add more of these templates as existing bindings in cxx-qt-lib. As then the developer can cast any T* to a QObject* and give it to invokeMethod. But the variable arguments makes this complex so i'm unsure what this would look like (maybe a macro helpers here?). Although the Qt meta object system allows for these slightly loose coupling (although you still need knowledge of the names of the methods/signals and the arguments, so how different is that to knowing the full type? or once we have casting, how different is this to knowing an Abstract type with just the signals/methods you care about?), I would also consider how your backend and frontend are split. As generally we encourage CXX-Qt to just be used for backend purposes and still use QML/JS or QtWidgets/C++ for frontend logic, eg build a QAbstractItemModel in Rust, but then connect to signals and link the view in the frontend. But maybe this is something that will improve over time. For the signals only using lambda this is known that we can only connect with lambdas, it is hard to currently see an API that could work on the Rust side to prove at compile time that a normal connection between a signal and slot exist. Maybe something we can improve in the future though. In general yes this issues are a lot of the remaining pain points / hard parts of CXX-Qt, if we can find a way to improve them then we would likely go that route. But some of these are limited by CXX itself or attempting to think of what an API would look like in Rust etc. Any suggestions for them and how they could work are of course welcome to be discussed ! :-) |
Beta Was this translation helpful? Give feedback.
-
Hi there!
I am back again with some questions.
I have to say first of all that I am happily using cxx-qt at the moment. That being said I keep running into similar problems that require solutions I'd rather not use. I am curious about your perspective and whether these issues would be in scope for future changes to cxx-qt.
Qt's meta-objects mechanism is touted by Qt itself as a means of decoupling. Objects can communicate with each other while not being aware of each other directly by using named signals and slots - and don't need to know each other's exact type to do so.
From what I have seen so far, connecting signals and slots in cxx-qt is a bit limited. It seems there is no generic way to connect a Qt signal to a Qt slot of two objects by name. There are no bindings for QObject, QMetaObject and QMetaMethod types that allow leveraging Qt's meta typesystem.
cxx-qt object work great with QML, but I often encounter issues when trying to make things happen directly between cxx-qt or Qt objects. Some specific examples of things I find hard to do:
In my codebase I have added my own bridge modules for QObject and QQuickItem, including templates to convert any cxx-qt object to a generic "*mut QObject" in order to call various generic functions on them, as well as bridging C++ methods that call Qt's "invoke". But then I have to define specific variants of the "invoke" template in the bridge module, for every call I want to make (e.g. "invoke with one int argument", "invoke with return value", etc.) and also avoid rust name aliases for these to avoid linker errors. All just to be able to call an invokable on an object that may be coming from QML, Qt or cxx-qt without having to know its type.
To make these things happen I am constantly having to add unsafe blocks of code in Rust to do various reference/pointer conversions. I guess this could be considered an effect of Qt's API inherently not following Rust usual safety guidelines.
Is access to the meta-typesystem intentionally limited in cxx-qt, or could it be considered something to improve for the future?
Beta Was this translation helpful? Give feedback.
All reactions