[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