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

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        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