[Development] Converting types in Qt

André Pönitz apoenitz at t-online.de
Thu Jul 17 22:27:50 CEST 2014

On Thu, Jul 17, 2014 at 02:38:40PM +0200, Jędrzej Nowacki wrote:
> On Thursday 17 of July 2014 13:33:49 Daniel Teske wrote:
> > On Thursday 17 Jul 2014 13:28:10 Jędrzej Nowacki wrote:
> > > On Thursday 17 of July 2014 10:51:03 you wrote:
> > > > QVariant::operator== is not symmetric
> > > > 
> > > >      QDateTime dateTime = QDateTime::currentDateTime();
> > > >     
> > > >     QTime time = dateTime.time();
> > > >     
> > > >     qDebug() << (QVariant(dateTime) == QVariant(time));
> > > >     qDebug() << (QVariant(time) == QVariant(dateTime));
> > > > 
> > > > -->
> > > > false
> > > > true
> > > 
> > > We could make it symmetric, if you want.
> > 
> > A equals operator that is not symetric is broken. Such a class cannot be
> > reliably used in std nor qt containers. Or do you know which way around,
> > QList::contains uses the equals operation?
> The example above shows what happens in case of a missing conversion, in this 
> case QTime can be converted to QDateTime, but the QDateTime can not be 
> converted to the QTime. Fail.

The broad problem here is _too many_ conversions. In this case specifically
the QDate-to-QDateTime conversion.

> The operator was / is / will be broken. Even if we make it symmetric, it will 
> remain conceptually broken. It should compare QVariants and then (maybe) the 
> wrapped value, while currently it tries a fuzzy comparison of the wrapped 
> value only.  It should look more or less like that:

It does not have to remain broken. The only reason to not fix it 
right now are compatibility promises.

A trivial solution (and one of the few correct ones) is to consider
QVariants as equal if and only if they have identical type and their
typed values are the same, according to a (proper) equivalence relation
set up for this type.

Of course one can come up with more elaborate schemes to set up 
equivalency classes like putting all integral type into one bucket.
Some might even make sense. What won't work are chains of conversions
int - QChar - QString - QStringList without a direct conversion 
from int to QStringList.

> There are few ways to fix it, sorted from the smallest impact on a user code 
> base to a-bomb size:
> - Add conversion QDateTime -> QTime (Up to now only Olivier agreed with me 
> that it is ok to add a new conversions)

Not acceptable. This loses precision, and consequently can't be made
transitive, i.e. there will be objects a, b, and c such that a == b, b == c,
with a != c.

> - If two QVaraints are not equal we can check if swapping left and right sides 
> helps. Inefficient, another behavior change and as odd as the current behavior. 
> Nothing to gain really.

Not acceptable. Albeit ths would solve the symmetry problem, the
transitivity problem remains.

> - Always compare QVariants twice left to right and right to left. Terribly 
> inefficient, more sensible output. Big behavior change as most of comparison 
> would return false.

Not acceptable. The ransitivity problem remains. We are looking in the
right direction, though: Things are less often equal than it appears to be

> - Allow comparisons of the same types or if there is explicitly registered 
> comparisons otherwise return false. Completely different behavior then the 
> current one.

[*] Acceptable for Qt 6 (and for Qt 5 as opt-in, due to the changed behaviour)
if and only if the "explicitly registered comparison functions" don't
violate any of the symmetricy/transitive/reflexive requirements.

> - Do not allow QVariant comparison, we can not support custom types if they do 
> not register conversion anyway so why bother.

Acceptable for Qt 6 (and for Qt 5 as opt-in, due to the changed behaviour),
but overshooting. QVariants of the same type with usable comparison for
that type are perfectly comparable.

The solution is [*].


More information about the Development mailing list