Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-58296

QVariant::isNull() must return true for nullptr_t

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.9.0 Beta 2
    • 5.8.0 RC
    • Core: Other
    • None
    • Qt 5.8.0 RC, any OS

    Description

      In Qt 5.8 we see many changes, and one of these is std::nullptr_t became registered type which is meant to be use for null values.

      So, for example, if in C++ we get QVariant value from QML, and this value was set to null in QML, then QVariant::isNull() returns false. And user has to write ugly code like this:

      if(value.isNull() || static_cast<QMetaType::Type>(value.type()) == QMetaType::Nullptr)
      {
          // The value is null, or default object for a type
      }
      else
      {
          // In this branch we can try convert value to C++ types
      }
      

      instead of something like this:

      if(value.isNull())
      {
          // The value is null, or default object for a type
      }
      else
      {
          // In this branch we can try convert value to C++ types
      }
      

      Other example is:

      int main() {
          QVariant v1 = QVariant::fromValue<void*>(nullptr);
          QVariant v2 = QVariant::fromValue(nullptr);
          qDebug() << v1.isNull() << v2.isNull() << (v1 == v2) << (v2 == v1);
          qDebug() << v2.canConvert<void*>() << v2.canConvert<QObject*>();
      }
      // output:
      // "false false false false" 
      // "false false"
      

      I agree with the author of this example (Olivier) and I also think that it is wrong. Because it goes against of semantic of the isNull() method name.
      In the discussion there are some posts against Olivier, but I think it is better for future releases to fix it now.

      One of the possible solutions is based on the post:

      QVariant's only pointer constructor is the one for const char*, which will be
      null if the pointer is null too. That would support the proposition that
      QVariant(nullptr).isNull() because QVariant((const char*)nullptr).isNull().

      However, to create a VoidStar, you need to write:

      QVariant::fromValue<void *>(nullptr);

      which does

      return QVariant(qMetaTypeId<T>(), &t, QTypeInfo<T>::isPointer);

      That constructor always sets d.is_null = false. So the QVariant is not null,
      as it contains a valid VoidStar value. It just happens that the VoidStar
      itself is null. In other words, QVariant behaves like a non-null void**
      pointing to a null void*.

      So, maybe it should check the pointer value in QVariant(qMetaTypeId<T>(), &t, QTypeInfo<T>::isPointer) constructor and if isPointer and *t is null then set d.is_null = true

      P.S. You could read the discussion in these links:
      http://lists.qt-project.org/pipermail/development/2016-September/027370.html

      http://development.qt-project.narkive.com/YnH0ceXV/behaviour-change-in-qml-in-qt-5-8-regarding-null

      P.P.S. I think it must to be fixed before the final release of Qt 5.8.0, because later it will harder to change the behavior in public API, IMHO.

      Attachments

        For Gerrit Dashboard: QTBUG-58296
        # Subject Branch Project Status CR V

        Activity

          People

            allan.jensen Allan Sandfeld Jensen
            ildar Gilmanov Ildar
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes