[Development] Converting types in Qt
Olivier Goffart
olivier at woboq.com
Tue Jul 15 11:59:03 CEST 2014
On Tuesday 15 July 2014 08:55:29 Jędrzej Nowacki wrote:
> Hi,
>
> I would like to discuss type conversions in Qt. As you may know, Qt has
> the ability to convert a known type to another known type. This works for
> trivial cases like, for example, "int" to "long", but also for more complex
> ones like "QByteArray" to "QString" or "CustomType" to "OtherCustomType".
> Type conversion in Qt happens mostly without user interaction, for example
> in QObject introspection or in QML, but it also can be used through public
> API: - QVariant::convert -> converts wrapped value to target type
> - QVariant::canConvert -> fast check if it may be possible to convert
> wrapped type to a given target, which is, in my opinion, pretty useless,
> unless the real conversion is really heavy
> - QMetaType::registerConverter -> allows to register a custom converter
> function for a user defined type
> - QMetaType::convert -> perform conversion between two types
>
> I would like to agree on some rules, regarding conversions, as the
> current approach is chaotic:
>
> 1. Are we allowed to add new conversions?
>
> The question is tricky because adding a new conversion is a behavior
> change, as this code:
> if (variant.canConvert(QMetaType::int)) ...
> may work differently. If we add custom types into the mix, everything
> is even more complex.
I'd say yes, for sensible conversion
You are right that it is a behaviour change, but i think it is worth changing
it.
> 1.1 Patch release or minor release only? [...]
Minor release only of course.
Path release is only for regressions and critical fixes. New conversions is a
feature.
> 1.2 Should conversion be perfect or based on a best effort?
>
> Some of the conversion API returns a "bool" value which is a status
> of conversion. What should it return if a conversion is not perfect, for
> example "int(-1) -> uint" or "QVariantList{string, int, myobject} ->
> QStringList", should such a case be detected? How do we define the perfect
> conversion? Sometimes only ideal, data lossless, conversions should be
> allowed, for example QtTestLib is quite strict about it and it allows only
> safe conversions. So, for example, "int -> long" but not "uint -> int", but
> I guess for normal use cases such strictness is not necessary.
> I think we should base conversions on the best effort and set the
> status to false only if a conversion failed completely, that is mainly if a
> conversion is unknown or if underlying implementation detected a failure,
> like "QByteArray -> float" which uses QByteArray::toFloat(bool *ok)
You have to think of the use cases for QVariant::convert.
Most common are things like QVariant::toString and QVariant::toInt and such.
You usually have a function that expect a string or an int, and you do best
effort to get that from the QVariant to ease programmer life in the wonderful
wold of dynamic typing :-)
It is true that it would be good to have a bool *ok in case the conversion
failed totally.
> 1.3 Should we try to support a user's type conversions out of the box?
>
> Currently a user needs to manually register a conversion function
> so Qt can know it and use it. For certain types we can do much better,
> because we can automatically convert some types. For example:
> QVector<char> -> QLinkedList<int>
> QList<Foo> -> QVector<Foo>
> QPointer<Foo> -> QObject*
> QPointer<Foo> -> void*
> QSharedDataPointer<Foo> -> bool
> MyQObject* -> QPointer<MyQObject>
> Currently we are not doing it for one reason which is behavior
> compatibility. What if a user already defined a conversion that we want to
> add? It could happen because the conversion was not available in a previous
> Qt version. The problem is that the new conversion function may behave in a
> different way, especially in edge cases and because of the lack of
> perfection mentioned in 1.2. We need to pick only one function. That could
> be the Qt version, but then we risk that an existing code will not work
> anymore. Are we willing to accept that?
> I believe that we should document the problem, and allow the
> conversions.
I think we could try to automatically do conversion when we know how to do it.
And if there is an user defined conversion, it overrides the automatic one.
> 1.4 Should a user be able to add Qt types conversion on his own?
>
> Some conversions are missing, some we consider as not safe. A user,
> assuming that he knows what he is doing, could register a conversion; for
> example, "QString -> QChar", how bad is it? Currently, such usage is
> blocked, because we are afraid that in the future we may add a conversion
> that overrides it.
> In my opinion it is not needed; it is a corner case, because we a)
> should have the conversion and then it will appear in a future version b)
> the conversion is invalid, and it is a sign of a user's broken code.
I'd say no.
> 2. Can we modify an existing conversion?
>
> All modification changes behavior. Of course we assume that changes are
> sensible, but still it may break existing code.
> 2.1 Can we improve a conversion?
>
> For example, "QStringList -> QString" is very tempting, as it works
> only if the list is of size 1. The conversion could join all strings
> instead, it would be almost backward compatible, as we would alter only
> conversions that failed previously.
> I believe we should allow that; I can not wait for the
> bike-shedding about which character or string we should use to join them.
I'd say yes.
>
> 2.2 How much we can break?
>
> Is missing data in the result of a conversion a reasonable cause to
> break behavior? For example "QVariant(QColor) -> QString" doesn't include
> the alpha channel (QTBUG-37851).
That should be fixed.
> As I said in 1.2, I think that we should take the approach of the
> best effort and nobody should depend on the exact result of a conversion. We
> should reserve our right to improve it, so the best effort is not a lie.
Yes
> 2.3 How to decide if a conversion should be improved?
>
> A conversion may be arbitrary. For example, most of the conversions
> to QString. Should "bool(false) -> QString" return "False", "0", "false"?
> What about precision of, for example, "double -> QString" ?
We use common sense on a case by case basic.
> 3. Can we remove existing conversions?
>
> I would say, no, but maybe in a major release.
Probably not.
--
Olivier
Woboq - Qt services and support - http://woboq.com - http://code.woboq.org
More information about the Development
mailing list