Re: [Development] Converting types in Qt
On Thursday 17 July 2014 21:31:31 André Pönitz wrote: PS: Random side-track question: How comparable are values of type 'int' and 'QUrl' if one applies 'common sense'? I even accept answer related to non-0 int values only. The trouble with common sense is that it is not very common in any sense - neither do a lot of people have it, nor do the remainder share a common vision of it... ;-) I'll try anyway... Intuitive answer without a specific use case in mind: they are not comparable at all - an int is a completely different beast from a URL. Answer with weird use cases in mind: the int could represent the path of a relative URL. E.g. I could create a cache directory in which I enumerate my resources with a simple int counter (cyrus IMAPd does something similar for mail storage) and finally express this as a relative URL - as a transient conversion int-string-URL. I could also imagine the int representing the host (IPv4 address) or port of the URL, but it gets really weird once you attempt to go there with automatic conversions and try to reconcile the result with RFC3986. In short: an int is just too ambiguous in relation to a URL to justify an automatic conversion. Konrad ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 16, 2014, at 1:45 PM, Poenitz Andre andre.poen...@digia.com wrote: Olivier Goffart wrote: Jędrzej Nowacki wrote: [...] What is wrong with string - int or bytearray - int? At the very least, _implicit_ conversions should not lose data, i.e. a A a1; B b = a1; A a2 = b; round trip ideally should yield a1 == a2. If I am ready to give up information, I'd like to need to say so in the code explicitly. (And yes, part of the deed is done in the core language, but even there compilers start to nag about it.) André, QVariant conversions are not implicit, they are explicit. I am aware of that. I tried to answer the question of What is wrong with string - int or bytearray - int”. 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 admittedly left the original context here (and in other parts of the discussion), but the question was posed in context that I read an example of an conversion that one would always consider convenient to have, and I started with At the very least, _implicit.. supposedly setting the context of the answer. Anyway. To summarize my position in the original context: QVariant is as it is. It is convenient at times, and it is already too convenient at times. Easy type conversion is a different use case than Type agnostic storage. QVariant does a bit of both, only the second one has ever been useful _to me_, I have been bitten by the first. As there are typically also more direct ways to convert types than to pass through QVariant, I consider the possibility to do type conversion through QVariant a mis-feature, and adding even more conversion abilities would be a step into the wrong direction _for me_. This is a personal opinion. Andre' -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Tuula Haataja Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
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. My recommendation is to not use the comparison at all. If you want more features of QVariant you can look into isNull() this is a perfect randomizer :P. The whole discussion took wrong direction. I didn't want to discuss QVariant API, which is not fixable, even Qt6 would not help, to much staff depends on it. Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
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? daniel ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Thursday 17 July 2014 13:33:49 Daniel Teske wrote: 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? Note that none of the class which have a member operator== is symmetric. Most of the class had an operator== as a member in Qt4 but that was a design mistake. New classes should have a friend operator== instead. Example: qDebug() (QUrl() == QString()); // true qDebug() (QString() == QUrl()); // compilation error That's because QUrl has a bool QUrl::operator==(const QUrl); Instead of bool operator==(const QUrl , const QUrl); The later is symmetric, but the former is not. This is also valid for operator and related. (That was just to go a bit more out of topic :-)) -- Olivier Woboq - Qt services and support - http://woboq.com - http://code.woboq.org ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
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 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: bool operator ==(const QVariant left, const QVariant right) { return left.userType() == right.userType() !QMetaType::compare(left.constData(), rigth.constData(), left.userType()); } To make it more ridiculous, currently it would not work as QMetType::compare do not know about built-in types :P 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) - 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. - 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. - Allow comparisons of the same types or if there is explicitly registered comparisons otherwise return false. Completely different behavior then the current one. - Do not allow QVariant comparison, we can not support custom types if they do not register conversion anyway so why bother. Cheers, Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 17, 2014, at 2:38 PM, Jędrzej Nowacki jedrzej.nowa...@digia.com 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. Actually, adding a conversion QTime - QDateTime wouldn’t help, because that conversion cannot “invent” the correct missing date information. So, QVariant(dateTime) == QVariant(time) would still fail, because the date of the datetime that is created when converting time-datetime will not be the same as the original datetime. In the presence of lossy conversions, you need to do conversions in both directions to make operator== symmetric. 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: bool operator ==(const QVariant left, const QVariant right) { return left.userType() == right.userType() !QMetaType::compare(left.constData(), rigth.constData(), left.userType()); } To make it more ridiculous, currently it would not work as QMetType::compare do not know about built-in types :P 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) - 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. - 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. - Allow comparisons of the same types or if there is explicitly registered comparisons otherwise return false. Completely different behavior then the current one. - Do not allow QVariant comparison, we can not support custom types if they do not register conversion anyway so why bother. Cheers, Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Tuula Haataja Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 17, 2014, at 1:28 PM, Jędrzej Nowacki jedrzej.nowa...@digia.com 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. My recommendation is to not use the comparison at all. If you want more features of QVariant you can look into isNull() this is a perfect randomizer :P. The whole discussion took wrong direction. I didn't want to discuss QVariant API, which is not fixable, even Qt6 would not help, to much staff depends on it. Well, the discussion is still sort of the same (and sort of not). The original question was, if we can/should add new type conversions, and/or which kind of conversions these could be. I think the investigations here about the API and workings of QVariant give some hints on what an answer to that might be. There is no need to expose the brokenness of the API even more by adding conversions that trigger it. operator== would be less bad if there were only symmetric and lossless conversions, so do not introduce any additional lossy or asymmetric conversions. Also, the uses of QVariant::toString (fromString), that we have found in Qt Creator ((de)serialization of QVariantMaps), definitely break if this conversion is *not* lossless (or not symmetric). int - long” kind of conversions might be sort of ok-ish, since the actual conversion can still fail if the long doesn’t fit into int, i.e. for values that actually fit into both types the conversion is lossless, for values that do not fit into both types, the conversion fails in one direction, and is not possible to start with in the other direction. Since this can only be found out during runtime, I’d try to avoid that though, and definitely not put that into the extreme. I would avoid conversions between containers that do not have the exact same type. QLinkedListT = QVectorT” maybe, “QLinkedListint = QVectorlong” ... no. Do not add conversions that do not have a “canonical way” to do it, and which do not have a corresponding toXXX function without parameters in the corresponding types. The exception to the “canonical way rule *might* be toString/fromString conversions, because of its usefulness. There is no canonical way to convert bool - string, but it might be useful for things like (de)serialization. (I’m not very convinced of toString conversion being very useful in the MVC context, actually, except maybe for quick-hack-debugging. For production you should be in better control of what you show to your user. I’m only half-convinced about its usefulness for (de)serialization.) Taking QString out of the rule has the disadvantage that it makes it harder if you actually want to hold string “data” in your variant (for which you would want saner conversion rules). Br, Eike -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Tuula Haataja Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Thu, Jul 17, 2014 at 02:36:22PM +0200, Olivier Goffart wrote: On Thursday 17 July 2014 13:33:49 Daniel Teske wrote: 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? Note that none of the class which have a member operator== is symmetric. Most of the class had an operator== as a member in Qt4 but that was a design mistake. New classes should have a friend operator== instead. Example: qDebug() (QUrl() == QString()); // true qDebug() (QString() == QUrl()); // compilation error That's because QUrl has a because is the bigger half of a red herring here. bool QUrl::operator==(const QUrl); Instead of bool operator==(const QUrl , const QUrl); The later is symmetric, but the former is not. The fact that the former is asymmetric is indeed not nice, already for esthetic reasons. But the fact that it actually _hurts_ is only due to the non-explicit QUrl(const QString url, ParsingMode mode = TolerantMode) constructor. If that is not available, e.g. after #define QT_NO_URL_CAST_FROM_STRING, neither version compiles. That's symmetric, and good. This is also valid for operator and related. (That was just to go a bit more out of topic :-)) We are still on track. The topic is free type conversion cause trouble, or Why there shouldn't be more type conversions through QVariant. Andre' PS: Random side-track question: How comparable are values of type 'int' and 'QUrl' if one applies 'common sense'? I even accept answer related to non-0 int values only. ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
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 convienient. - 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 [*]. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 15, 2014, at 7:36 PM, Olivier Goffart oliv...@woboq.com wrote: On Tuesday 15 July 2014 10:38:52 Poenitz Andre wrote: Olivier Goffart wrote: Jędrzej Nowacki wrote: 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. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. 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: QVectorchar - QLinkedListint QVectorchar v; v.append(130); QLinkedListint l = /*someSensibleAutomatedConversion*/(v); assert(l.first() == 130) ? Depends ? QVariant(char(130)).toInt() already exists. You may argue that it is not sensible but that's another issue. I guess the example is more between QVectorT1 - QLinkedListT2 when there exist a conversion from T1 to T2 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. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. What's the mistake here? Wrong encoding? Bad performances? wrong values unexpected results When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. I don’t think we have a single place in Qt Creator where we want automatic conversions when using QVariant. A search for QVariant(Map) returns 5400 hits. In the map case, we usually expect the one retrieving the value for a key to know the exact type of what was thrown in (that’s usually the same class, or related classes), and then we use item models and QSettings which we use in the same way. Even if automatic conversion might be interesting (when, actually?), then the point is: There is no API in QVariant to support the common use case of getting the value *without* automatic conversion. We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? Br, Eike -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Tuesday 15 of July 2014 11:59:03 Olivier Goffart wrote: 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: QVectorchar - QLinkedListint QListFoo - QVectorFoo QPointerFoo - QObject* QPointerFoo - void* QSharedDataPointerFoo - bool MyQObject* - QPointerMyQObject 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. We could implement overriding, but we would not control which conversion is registered first / last. Moreover it would mean that a conversion could change at any point. I think it would be a bit too nondeterministic. Cheers, Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Tuesday 15 of July 2014 10:38:52 Poenitz Andre wrote: Olivier Goffart wrote: Jędrzej Nowacki wrote: 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. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? Yes. Because there are two separate issues here. One is that the build time sometimes doesn't exist, and you do not want to break an application that had no opportunity to rebuild. Second is that I'm not talking about abstract foo or bar function. I was explicit what would change, it would be Qt answer for a simply question could you convert this value to this type. I guess in most cases the question would be placed in a context: could you convert this value to this type, because I know only how to handle the type and not any other. In my opinion it is good to answer the question with yes. 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: QVectorchar - QLinkedListint QVectorchar v; v.append(130); QLinkedListint l = /*someSensibleAutomatedConversion*/(v); assert(l.first() == 130) ? Depends ? Invalid code = undefined output. You can simplify the example to: QVectorchar v; v.append(130); assert(v.first() == 130) ? Depends ? The issue has nothing to do with a magic conversion. You can blame C++ standard, which doesn't specify if char is signed or not, or people that write such code. I guess both options are valid :-) 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. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. You are right, it is good to avoid it, but sometimes it is not possible especially, if you do not control full stack. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Olivier Goffart wrote: I'd say yes, for sensible conversion You are right that it is a behaviour change, but i think it is worth changing it. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. Type safety is a safety net that catches errors very early in the software production and deployment cycle, and one of the features that makes a programming language usable for the development of large applications at a reasonable pace. Implicit type conversions kill type safety. This is widely recognized as a bad thing. In case of C++ some are unavoidable due to the C legacy, but e.g. for user-defined conversion operators we now got explicit, _because_ people learned the hard way that implicit conversions are causing more trouble than wanted. [...] We use common sense on a case by case basic. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. What's the mistake here? Wrong encoding? Bad performances? Wrong encodings under circumstances that are typically not present on the developers or test machines. Here the lack of type safety postpones a problem that would be immediately visible (and fixable) at compile time, to the time after the application has been shipped. In the best case this only causes a bug report that needs to be handled normally, i.e. needs triaging/fixing/integration (and hopefully is not so critical to require an immediate emergency release, but can be delivered with the next regular one). Worst case this could mean that the application is unusable in a larger part of the world. With or without someone reporting the problem. This is a kind of convenience I don't need, and I pretty much prefer the inconvenience of having to spell out type conversions explicitly. When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. I wholeheartedly disagree. Most of my QVariant uses are there because the Qt API requires me to use it, and I sometimes use it voluntarily for type-agnostic storage or transport of things. But in those cases I never want to extract anything else from the variant than exactly the thing I put into it. I _never_ (at least not intentionally) use QVariant as a kind of magic converter bag where I put something in and get something conveniently munged back. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 July 2014 08:41:07 Poenitz Andre wrote: I wholeheartedly disagree. Most of my QVariant uses are there because the Qt API requires me to use it, and I sometimes use it voluntarily for type-agnostic storage or transport of things. But in those cases I never want to extract anything else from the variant than exactly the thing I put into it. So if I understand you and Eike correctly, what you want is some kind of templatetypename T T qvariant_cast_safe(const QVariant v) { Q_ASSERT(v.userType() == qMetaTypeIdT()) return *reinterpret_castconst T *(v.constData()); } I _never_ (at least not intentionally) use QVariant as a kind of magic converter bag where I put something in and get something conveniently munged back. When you play with qml or itemview, it's cool that there is a QVariant::toString() that puts some string out in order to show to the user what's in it. -- Olivier Woboq - Qt services and support - http://woboq.com - http://code.woboq.org ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 of July 2014 06:37:25 Ziller Eike wrote: [...] When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. I don’t think we have a single place in Qt Creator where we want automatic conversions when using QVariant. A search for QVariant(Map) returns 5400 hits. In the map case, we usually expect the one retrieving the value for a key to know the exact type of what was thrown in (that’s usually the same class, or related classes), and then we use item models and QSettings which we use in the same way. Even if automatic conversion might be interesting (when, actually?), then the point is: There is no API in QVariant to support the common use case of getting the value *without* automatic conversion. Nobody asked for it, It should be easy to implement something equal to this; Q_ASSUME(variant.userType() == qMetaTypeTargetType()); TargetType data = variant.valueTargetType(); I believe such new api make sense, we can add it. We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? Br, Eike What is wrong with string - int or bytearray - int? -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 of July 2014 08:41:07 Poenitz Andre wrote: Olivier Goffart wrote: I'd say yes, for sensible conversion You are right that it is a behaviour change, but i think it is worth changing it. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. Type safety is a safety net that catches errors very early in the software production and deployment cycle, and one of the features that makes a programming language usable for the development of large applications at a reasonable pace. Implicit type conversions kill type safety. This is widely recognized as a bad thing. In case of C++ some are unavoidable due to the C legacy, but e.g. for user-defined conversion operators we now got explicit, _because_ people learned the hard way that implicit conversions are causing more trouble than wanted. That is a controversial statement. There is many languages, that doesn't offer strict type safety and they are fine. Let's no go into this discussion because it would lead us nowhere. [...] We use common sense on a case by case basic. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. What's the mistake here? Wrong encoding? Bad performances? Wrong encodings under circumstances that are typically not present on the developers or test machines. Here the lack of type safety postpones a problem that would be immediately visible (and fixable) at compile time, to the time after the application has been shipped. In the best case this only causes a bug report that needs to be handled normally, i.e. needs triaging/fixing/integration (and hopefully is not so critical to require an immediate emergency release, but can be delivered with the next regular one). Worst case this could mean that the application is unusable in a larger part of the world. With or without someone reporting the problem. This is a kind of convenience I don't need, and I pretty much prefer the inconvenience of having to spell out type conversions explicitly. In this particular case I would blame QSettings API, which pretends that is able to handle everything while it is not. When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. I wholeheartedly disagree. Most of my QVariant uses are there because the Qt API requires me to use it, and I sometimes use it voluntarily for type-agnostic storage or transport of things. But in those cases I never want to extract anything else from the variant than exactly the thing I put into it. I _never_ (at least not intentionally) use QVariant as a kind of magic converter bag where I put something in and get something conveniently munged back. Actually I agree, I believe that QVariant should be just a stupid container which allows you to transfer a data in type agnostic way, from one place to another. Well, during it lifetime it accumulated a bit of additional functionality, but I see that the discussion is floating in wrong direction. Let's not talk about implicit QVariant conversions, we have them and we can not remove them. We can add, as Olivier suggested qvariant_type_safe_cast to our API. Let's talk about QMetaType::convert and QmetaType::hasRegisteredConverterFunction, instead are we allowed to change their behavior by adding / modifying conversions ? Jędrek Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Olivier Goffart: Poenitz Andre wrote: I wholeheartedly disagree. Most of my QVariant uses are there because the Qt API requires me to use it, and I sometimes use it voluntarily for type-agnostic storage or transport of things. But in those cases I never want to extract anything else from the variant than exactly the thing I put into it. So if I understand you and Eike correctly, what you want is some kind of templatetypename T T qvariant_cast_safe(const QVariant v) { Q_ASSERT(v.userType() == qMetaTypeIdT()) return *reinterpret_castconst T *(v.constData()); } This would alleviate the environment dependency of the problem, i.e. presumably increase the probability that the issue is caught in local testing. (Of course, a real compile-time check i.e. something that would also catch errors in code paths that are not executed during testing would be preferable, but that's not achievable in this setup) I _never_ (at least not intentionally) use QVariant as a kind of magic converter bag where I put something in and get something conveniently munged back. When you play with qml or itemview, it's cool that there is a QVariant::toString() that puts some string out in order to show to the user what's in it. That's a one-way route for a specific purpose, pretty much like qPrintable(). There's nothing wrong with a .toDisplay() (or similar) function, but that's don't think this is the kind of type conversion that triggered this thread. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 July 2014 08:41:07 Poenitz Andre wrote: Olivier Goffart wrote: It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. Type safety is a safety net that catches errors very early in the software production and deployment cycle, and one of the features that makes a programming language usable for the development of large applications at a reasonable pace. I feel I need to clear up some misconceptions here: the kind of type safety offered by C++ is a possibility, but not a necessity for fast and safe development of large applications. I've done Smalltalk for quite some time - it does not have a static type system like C++ and development is still faster than in most C++ based environments - I'd even go as far as saying it is slightly faster to develop with Smalltalk than it is to develop with Qt (I still prefer Qt for its more modern API). The key is usually great documentation, good tooling, good APIs and fast turn-around from adding a few lines to seeing them in action (in the last point C++ can't even hope to compete with Smalltalk, the other three are quite good with Qt). Implicit type conversions kill type safety. This is widely recognized as a bad thing. In case of C++ some are unavoidable due to the C legacy, but e.g. for user-defined conversion operators we now got explicit, _because_ people learned the hard way that implicit conversions are causing more trouble than wanted. Let's not mix up too much here: type conversions are necessitated by the fact that C++ has static typing - otherwise you would not get much done with it - from the Smalltalk point of view C++ is not polymorphic. Implicit type conversions are necessitated by the fact that programmers (like me) are lazy bastards and don't like to read lines which are longer than a couple of words. The explicit keyword is just a way of telling the compiler that a constructor is NOT a type conversion - however, I'm not entirely sure whether it was such a brilliant idea to have two kinds of implicit user defined conversion (constructors and type operators). So, just get used to the idea of prefixing each constructor with an explicit and only consider removing it again afterwards. This is a kind of convenience I don't need, and I pretty much prefer the inconvenience of having to spell out type conversions explicitly. Reminds me of the early days of Java - almost every cast was explicit and you wrote endless lines of casts just to get a very simple resource. Thanks, but no thanks. In short: you need a certain amount of convenience to not hinder the programmer. Too much magic in the background and it is just as bad. The difficulty seems to be to define the ideal point between convenience and shooting yourself into the foot all the time. As long as QVariant mirrors the abilities of C++ (i.e. only using implicit conversions that are also available in plain C++, plus maybe a few very obvious ones, like toString) we are fine. More and we'll get weird bug reports, less and programmers will constantly bitch about it. BTW: you can already implicitly cast QByteArray-QString, so why not allow it through QVariant? Konrad ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Jędrzej Nowacki wrote: Eike wrote: [...] We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? What is wrong with string - int or bytearray - int? At the very least, _implicit_ conversions should not lose data, i.e. a A a1; B b = a1; A a2 = b; round trip ideally should yield a1 == a2. If I am ready to give up information, I'd like to need to say so in the code explicitly. (And yes, part of the deed is done in the core language, but even there compilers start to nag about it.) Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 16, 2014, at 11:28 AM, Jędrzej Nowacki jedrzej.nowa...@digia.com wrote: On Wednesday 16 of July 2014 06:37:25 Ziller Eike wrote: [...] When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. I don’t think we have a single place in Qt Creator where we want automatic conversions when using QVariant. A search for QVariant(Map) returns 5400 hits. In the map case, we usually expect the one retrieving the value for a key to know the exact type of what was thrown in (that’s usually the same class, or related classes), and then we use item models and QSettings which we use in the same way. Even if automatic conversion might be interesting (when, actually?), then the point is: There is no API in QVariant to support the common use case of getting the value *without* automatic conversion. Nobody asked for it, It should be easy to implement something equal to this; Q_ASSUME(variant.userType() == qMetaTypeTargetType()); TargetType data = variant.valueTargetType(); I believe such new api make sense, we can add it. We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? Br, Eike What is wrong with string - int or bytearray - int? First of all I wondered what bytearray - int does at all. Convert the first byte in the byte array to an int, if bytearray.size() == 1 (which would be consistent with QStringList-QString)? bytearrays are not strings after all… Otherwise bytearray/string - int has similar problems as string - bool and string - bytearray: There is no canonical “right” way to do it, and it can fail depending on the actual *value*. Does QVariant::canConvert actually take that into account? Is there any other possibility to find out if it went wrong? Does it interpret 0xa1 ? Will 076 be interpreted as octal or decimal? Does it convert “ퟷ” (U+1D7F7) to 1 ? ;) All in all it creates more questions than it solves problems. There are no QKeySequence::toInt(), QString::toBool(), QString::toByteArray() functions btw, and QString/QByteArray::toInt(…) take arguments. I think one prerequisite for possible conversions (automatic or not) should be, that a corresponding ::to… function without any arguments in the corresponding type would survive an API review, and actually is added as well. Then one also has a place to look for documentation how the actual conversion is done. Br, Eike -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 16, 2014, at 11:58 AM, Konrad Rosenbaum kon...@silmor.de wrote: On Wednesday 16 July 2014 08:41:07 Poenitz Andre wrote: Olivier Goffart wrote: It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. Type safety is a safety net that catches errors very early in the software production and deployment cycle, and one of the features that makes a programming language usable for the development of large applications at a reasonable pace. I feel I need to clear up some misconceptions here: the kind of type safety offered by C++ is a possibility, but not a necessity for fast and safe development of large applications. I've done Smalltalk for quite some time - it does not have a static type system like C++ and development is still faster than in most C++ based environments - I'd even go as far as saying it is slightly faster to develop with Smalltalk than it is to develop with Qt (I still prefer Qt for its more modern API). The key is usually great documentation, good tooling, good APIs and fast turn-around from adding a few lines to seeing them in action (in the last point C++ can't even hope to compete with Smalltalk, the other three are quite good with Qt). Implicit type conversions kill type safety. This is widely recognized as a bad thing. In case of C++ some are unavoidable due to the C legacy, but e.g. for user-defined conversion operators we now got explicit, _because_ people learned the hard way that implicit conversions are causing more trouble than wanted. Let's not mix up too much here: type conversions are necessitated by the fact that C++ has static typing - otherwise you would not get much done with it - from the Smalltalk point of view C++ is not polymorphic. Implicit type conversions are necessitated by the fact that programmers (like me) are lazy bastards and don't like to read lines which are longer than a couple of words. The explicit keyword is just a way of telling the compiler that a constructor is NOT a type conversion - however, I'm not entirely sure whether it was such a brilliant idea to have two kinds of implicit user defined conversion (constructors and type operators). So, just get used to the idea of prefixing each constructor with an explicit and only consider removing it again afterwards. This is a kind of convenience I don't need, and I pretty much prefer the inconvenience of having to spell out type conversions explicitly. Reminds me of the early days of Java - almost every cast was explicit and you wrote endless lines of casts just to get a very simple resource. Thanks, but no thanks. In short: you need a certain amount of convenience to not hinder the programmer. Too much magic in the background and it is just as bad. The difficulty seems to be to define the ideal point between convenience and shooting yourself into the foot all the time. As long as QVariant mirrors the abilities of C++ (i.e. only using implicit conversions that are also available in plain C++, plus maybe a few very obvious ones, like toString) we are fine. More and we'll get weird bug reports, less and programmers will constantly bitch about it. BTW: you can already implicitly cast QByteArray-QString, so why not allow it through QVariant? This can be considered an API fail, which is why you can explicitly turn off these type of conversions for your applications by defining QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII (which we e.g. do for Qt Creator). Br, Eike -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 July 2014 10:06:52 Poenitz Andre wrote: Jędrzej Nowacki wrote: Eike wrote: [...] We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? What is wrong with string - int or bytearray - int? At the very least, _implicit_ conversions should not lose data, i.e. a A a1; B b = a1; A a2 = b; round trip ideally should yield a1 == a2. If I am ready to give up information, I'd like to need to say so in the code explicitly. (And yes, part of the deed is done in the core language, but even there compilers start to nag about it.) André, QVariant conversions are not implicit, they are explicit. You have to use qvariant_castT, QVariant::valueT, or QVariant::to*. That's explicit. Conversions _to_ QVariant are sometimes implicit, but they are loss-less as it just wrap the type into the QVariant. -- Olivier Woboq - Qt services and support - http://woboq.com - http://code.woboq.org ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 of July 2014 12:51:36 Olivier Goffart wrote: On Wednesday 16 July 2014 10:06:52 Poenitz Andre wrote: Jędrzej Nowacki wrote: Eike wrote: [...] We use common sense on a case by case basic. Either there is no “common sense” common to me, or this rule has failed in the past already ;) bool - string ? bytearray - int/long/double ? keysequence - int ? string - bool ? string - bytearray ? string - int ? What is wrong with string - int or bytearray - int? At the very least, _implicit_ conversions should not lose data, i.e. a A a1; B b = a1; A a2 = b; round trip ideally should yield a1 == a2. If I am ready to give up information, I'd like to need to say so in the code explicitly. (And yes, part of the deed is done in the core language, but even there compilers start to nag about it.) André, QVariant conversions are not implicit, they are explicit. You have to use qvariant_castT, QVariant::valueT, or QVariant::to*. That's explicit. Conversions _to_ QVariant are sometimes implicit, but they are loss-less as it just wrap the type into the QVariant. True conversions from QVariant are explicit, but some of Qt API hides that, for example QObject::setProperty which tries hard to implicitly convert data, Ok, so Andre is in favor of ideal conversions (point 1.2). Ideal round trip conversion is possible only if A and B represent the same concept using a different representation. So it would work for QLinkedListT = QVectorT, but not for int - long. In my opinion it is really limiting and kind of opposite to what we have now :-) We could potentially split all conversions into two groups ideal and best effort and disallow usage of the second group in certain cases. I'm not sure if it is worth the effort, and definitely It would break existing behavior as effectively it would remove some of the conversions (point 3) Cheers, Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 of July 2014 06:37:25 Ziller Eike wrote: I don’t think we have a single place in Qt Creator where we want automatic conversions when using QVariant. A search for QVariant(Map) returns 5400 hits. In the map case, we usually expect the one retrieving the value for a key to know the exact type of what was thrown in (that’s usually the same class, or related classes), and then we use item models and QSettings which we use in the same way. From performance point of view it is good to avoid any conversions. I would say even more, if you know all types in your application there is no point in using QVariant. Sometimes it is not possible, and sometimes one just don't want be bothered. I made an extremely unfair experiment. I switched off all conversions in Qt and I recompiled QtCreator. To be honest I expected that it would crash at startup, but no (impressive!). I was able to use menu and open dialogs, nothing more. From the stderr I could deduct that a QVariant conversion was used in reading xml, qws files and in animations. Cheers, Jędrek ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Olivier Goffart wrote: Jędrzej Nowacki wrote: [...] What is wrong with string - int or bytearray - int? At the very least, _implicit_ conversions should not lose data, i.e. a A a1; B b = a1; A a2 = b; round trip ideally should yield a1 == a2. If I am ready to give up information, I'd like to need to say so in the code explicitly. (And yes, part of the deed is done in the core language, but even there compilers start to nag about it.) André, QVariant conversions are not implicit, they are explicit. I am aware of that. I tried to answer the question of What is wrong with string - int or bytearray - int. We admittedly left the original context here (and in other parts of the discussion), but the question was posed in context that I read an example of an conversion that one would always consider convenient to have, and I started with At the very least, _implicit.. supposedly setting the context of the answer. Anyway. To summarize my position in the original context: QVariant is as it is. It is convenient at times, and it is already too convenient at times. Easy type conversion is a different use case than Type agnostic storage. QVariant does a bit of both, only the second one has ever been useful _to me_, I have been bitten by the first. As there are typically also more direct ways to convert types than to pass through QVariant, I consider the possibility to do type conversion through QVariant a mis-feature, and adding even more conversion abilities would be a step into the wrong direction _for me_. This is a personal opinion. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Anyway. To summarize my position in the original context: QVariant is as it is. It is convenient at times, and it is already too convenient at times. Easy type conversion is a different use case than Type agnostic storage. QVariant does a bit of both, only the second one has ever been useful _to me_, I have been bitten by the first. As there are typically also more direct ways to convert types than to pass through QVariant, I consider the possibility to do type conversion through QVariant a mis-feature, and adding even more conversion abilities would be a step into the wrong direction _for me_. This is a personal opinion. I certainly can't recall any place in Creator where a conversion via QVariant was intended. I can though recall several instances where such a conversion was the source of bugs. daniel ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
Hi In the qml designer we are using comparisons of variants quite extensive and run in smaller problems like wrong conversions. E.g. color is broken because the alpha value is not used in the comparison. We would like to extent existing comparisons too because we get the variants from different sources, so the value is equal but because the conversion is not working it is not the same. Thomas Hartmann was running in more problems like that and if he is back in two weeks you should ask him. Best, Marco From: development-bounces+marco.bubke=digia@qt-project.org [development-bounces+marco.bubke=digia@qt-project.org] on behalf of Jędrzej Nowacki [jedrzej.nowa...@digia.com] Sent: Tuesday, July 15, 2014 8:55 AM To: development@qt-project.org Subject: [Development] Converting types in Qt 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. 1.1 Patch release or minor release only? I would say that new conversions may appear only in minor releases, obvious fixes to existing conversions may appear in patch releases, where by obvious I mean crash fixes and cases in which the returned value is definitely bogus. 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) 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: QVectorchar - QLinkedListint QListFoo - QVectorFoo QPointerFoo - QObject* QPointerFoo - void* QSharedDataPointerFoo - bool MyQObject* - QPointerMyQObject 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. 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
Re: [Development] Converting types in Qt
On Jul 16, 2014, at 1:30 PM, Jędrzej Nowacki jedrzej.nowa...@digia.com wrote: On Wednesday 16 of July 2014 06:37:25 Ziller Eike wrote: I don’t think we have a single place in Qt Creator where we want automatic conversions when using QVariant. A search for QVariant(Map) returns 5400 hits. In the map case, we usually expect the one retrieving the value for a key to know the exact type of what was thrown in (that’s usually the same class, or related classes), and then we use item models and QSettings which we use in the same way. From performance point of view it is good to avoid any conversions. I would say even more, if you know all types in your application there is no point in using QVariant. Sometimes it is not possible, and sometimes one just don't want be bothered. I made an extremely unfair experiment. I switched off all conversions in Qt and I recompiled QtCreator. To be honest I expected that it would crash at startup, but no (impressive!). I was able to use menu and open dialogs, nothing more. From the stderr I could deduct that a QVariant conversion was used in reading xml, qws files and in animations. True, we use QVariant::toString for an easy way to write the value of the key-value pairs of basic types in qtversions.xml, profiles.xml, .pro.user, and the sessions (.qws) Even there we keep the type information though, and use that to explicitly convert the variants in the map back to the right type when reading the file, so type conversion should never be outside the reader/writer in that case. What the conversion saves us, is a few case statements in the reader/writer. data variableQtVersion.0/variable valuemap type=QVariantMap value type=int key=Id10/value value type=QString key=NameQt 5.3/value value type=QString key=QMakePath/Users/Shared/qt/qt/5.3/64/qtbase/bin/qmake/value value type=QString key=QtVersion.TypeQt4ProjectManager.QtVersion.Desktop/value value type=bool key=isAutodetectedfalse/value /valuemap /data No idea what happens in animations, but I’d suppose that any conversions there would be accidentally. -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Wednesday 16 July 2014 15:01:53 Ziller Eike wrote: No idea what happens in animations, but I’d suppose that any conversions there would be accidentally. QPropertyAnimation is based on modifying QVariants, isn't it? -- Thiago Macieira - thiago.macieira (AT) intel.com Software Architect - Intel Open Source Technology Center ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Jul 16, 2014, at 5:04 PM, Thiago Macieira thiago.macie...@intel.com wrote: On Wednesday 16 July 2014 15:01:53 Ziller Eike wrote: No idea what happens in animations, but I’d suppose that any conversions there would be accidentally. QPropertyAnimation is based on modifying QVariants, isn't it? True, but I’d claim that that shouldn’t need automatic conversions between types. If I create a QPropertyAnimation on a “qreal” property, and set “qreal” start and end values, then there should not happen any automatic conversions. If I’d set end value “10.0” (i.e. QString), then I’d consider that very bad style. Maybe we have some int/real conversions happening there, which could at least argued to not do much harm. -- Eike Ziller, Senior Software Engineer - Digia, Qt Digia Germany GmbH, Rudower Chaussee 13, D-12489 Berlin Geschäftsführer: Mika Pälsi, Juha Varelius, Anja Wasenius Sitz der Gesellschaft: Berlin. Registergericht: Amtsgericht Charlottenburg, HRB 144331 B ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
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: QVectorchar - QLinkedListint QListFoo - QVectorFoo QPointerFoo - QObject* QPointerFoo - void* QSharedDataPointerFoo - bool MyQObject* - QPointerMyQObject 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
Re: [Development] Converting types in Qt
Olivier Goffart wrote: Jędrzej Nowacki wrote: 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. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? 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: QVectorchar - QLinkedListint QVectorchar v; v.append(130); QLinkedListint l = /*someSensibleAutomatedConversion*/(v); assert(l.first() == 130) ? Depends ? 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. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. Andre' ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development
Re: [Development] Converting types in Qt
On Tuesday 15 July 2014 10:38:52 Poenitz Andre wrote: Olivier Goffart wrote: Jędrzej Nowacki wrote: 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. Why? On one hand you promise binary compatibility. On the other hand behaviour changes are proposed to be done on an nice to have base? Do we really think that's ok to disallow changing some int foo() { return 42; } to some int bar() { return 42; } that's easy to discover at build time, but it's fine to change int foo() { return 42; } to int foo() { return -1; } ? It's always a dilemma. We have to look at how likely we are to break applications and I don't think adding a conversion is likely to cause breakages. 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: QVectorchar - QLinkedListint QVectorchar v; v.append(130); QLinkedListint l = /*someSensibleAutomatedConversion*/(v); assert(l.first() == 130) ? Depends ? QVariant(char(130)).toInt() already exists. You may argue that it is not sensible but that's another issue. I guess the example is more between QVectorT1 - QLinkedListT2 when there exist a conversion from T1 to T2 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. I tend to believe the common sense in type conversion land is pretty close to avoid to do it automatically, prefer to make it explicit. Already now it's far too easy to make mistakes based on the nice and easy QByteArray - QVariant - QString conversions when accidentally writing QByteArrays into QSettings and reading QStrings back. There shouldn't be more of that. What's the mistake here? Wrong encoding? Bad performances? When one use QVariant, it is because we want to enjoy dynamic typing and nice conversions. -- Olivier Woboq - Qt services and support - http://woboq.com - http://code.woboq.org ___ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development