Post by Olivier GoffartPost by Jedrzej NowackiHi everyone!
While main heat on the mailing list is taken by topic how to encode that we
are nice, friendly and respectful to each other, I would like to show some
side project that I had. It is a proposal for base of metatype system for
https://github.com/nierob/qmetatype. It is quite fresh and it was rather
a storage for functionality ideas. I haven't tried to compare performance
of it to the current system, but for sure it has more flexibility and I
believe, that conceptually it could serve us during Qt6. Anyway before
spending too much time on it I would like to get some early feedback and
questions.
The discussion in that other thread are not finished, so please wait until
there is consensus before being nice!
Well I prefer publish it now and work in the open. I do not expect everyone
jumping to the topic , dropping everything else, but at least some people can
look at the code :-) There is no rush, for me it is an achieved milestone. Now
the harder work slowly may happen.
Post by Olivier GoffartBut thanks for caring about the QMetaType system.
Thanks for looking at the code!
Post by Olivier GoffartI had a short look. I think it would be usefull if you already used names
closer to what they are supposed to be. Namespace N, P, are not so nice names.
N is next, P is private, kind of my personal standard.
Action point for me:
- updated P to QtPrivate
- see how many name clashes I will get after removing N.
Post by Olivier GoffartThe idea of using a single function with operation is quite a good idea I
like it. As long as the function takes the typeid as a parameter.
Indeed, I'm thinking about dynamic types that would come from language
bindings: in this situation, while it is easy to allocate memory on the
heap, it is not easy to create a new function pointer for every dynamic
type that we would register.
Let's postpone that discussion to a moment that we agree on the extensions.
Post by Olivier GoffartRegarding the extension, i don't know if it is such a good idea, because you
never know what you can rely on.
say you have a QVariant with some type that comes from some part of your
code, how do you know if you can print it with qDebug, or convert it to
string, how do you register that?
IMHO, there should not be extensions! All operation that we want to make
available for a type should be always available. Using SFINAE to find out if
it is available.
Extensions in that respect do not change anything, because it is about error
handling. How to inform a user that a type is not qdebug stream-able or can
not be converted to QString. In the current and the data driven approach you
would need to check if the right function pointer is null or not and on top of
this the error handling still would need to happen as the call itself could
fail. With the proposed solution you have only one point in which you handle
potential errors, just after the metatype call.
So let's return to QVariant concern that you expressed. I believe that if you
plan to use a feature you need to ensure that you can. So I would propose
QVariant constructor to look more or less like qVariantFromValue, it would do
the "registration" it needs. It is in sync with QObject registering own
properties types.
SFINAE would be used in extensions, as I showed in https://github.com/nierob/
qmetatype/blob/master/extensions/streams.h, still error handling is missing
there. Actually I think it is wrong layer for detection, creating dummy
handlers is wrong.
Action points for me:
- show in a better way that extensions can be added lazily
- improve error handling in metatype call
- highlight more common set of operations that would be used if qTypeId<T>()
is called
- move stream SFINAE detection a bit higher in the code stack
Post by Olivier Goffart- for QVariant, and the queued connections: copy / destruction. Ideally in
place. So we also need the size/alignement to be able to allocate the memory
- for qDebug, we need the QDebug operator <<
- for QDataStream, we need the operator << and >>, and an unique identifier
that stay the same. Currently, this is the type id for builtin types, and
the name for custom type. I suggest we use the name, if we want to keep
compatibility with old steam, we will need to keep a mapping from old type
id, to new name.
I'm pretty sure that you are aware that the list is far from being complete,
so I will not neat pick on this, but how you make sure that every future use
case would satisfied? Hiding functionality behind a function and extensible
data struct allow _us_ to extend it if _we_ believe that costs are worth the
gain, but it doesn't solve problem for 3rdparty code. We do see the problem
even in our modules that needs to keep a sibling mapping from typeid to some
functions, in particular dbus and qml(?).
Post by Olivier GoffartAs for the name, we can indeed find a way to extract it from parsing it from
__PRETTY_FUNC__ as you do. It would work on every compiler we support i
guess, but we need spcial code for that as it is not really standard.
Yes, it is compiler specific, but some version of the trick would work on all
supported compilers, I think. Even if not we could fallback to typeid() and
require RTTI on these potentially few weaker compilers, so my feeling is that
it is safe to use it.
Post by Olivier GoffartIn Qt5, we also need the name for the string-based connection syntax.
However, I believe we can do that without relying on the name
"as-seen-by-moc", if the moc generated code always register the types.
(this is already almost the case)
Why almost? Is it that because of forward declared types?
Post by Olivier Goffart- What about QSequentialIterable / QAssociativeIterable? We also need
something there.
Nothing really, currently it works through conversions. We could keep the way
or really extract a new API that allows to do same thing. It is slightly
orthogonal, unless I miss something.
Action point for me:
- prototype conversions
Post by Olivier GoffartPost by Jedrzej NowackiThe whole registry is kept behind a mutex and it is very central, the mutex
usage actually shows on profilers.
This used to be the case before Qt 5.7, but since then, QReadWriteMutex was
greatly optimized, does it still show in the profiler?
Hmm true, I do not know. The list was created from the top of my head.
Action point for me:
- remove the point
Post by Olivier GoffartYou will need that anyway, because relying on a static variable in a
function template does not work on MSVC as far as i know. (Last time i
tried was a long time ago, and they had different address and value in
different libraries) That's why we will probably need to initialize it with
a name lookup.
Ugh, that is an ugly problem. This https://github.com/nierob/qmetatype/blob/
master/metatype_impl.h#L80 one really requires the unification of variables.
You are right we can workaround it with a global registry and name lookup,
but... oh.
Post by Olivier GoffartIt is probably still a good idea to register builtin type at compile time,
since we want to save in registering time. There are some data structures
out there with compile time hash table that can be extended at runtime.
Yes, in addition we will need to have QMetaType::Type mapping anyway to keep
SC.
Action point for me:
- prototype the mapping
Post by Olivier GoffartSo the early feedback i can give on your code is that it is a bit more
complicated than necessary with the extension. and i think it can be simplified.
Because you are skipping one of the features that I would like to have. To be
discussed ;-)
Thank you!
Jędrek