Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. A small suggestion for improving Qt
QtWS25 Last Chance

A small suggestion for improving Qt

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 4 Posters 801 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Navadvipa Chandra das

    Hello, All!

    I want to suggest a small improvement to Qt. To do this, add two public virtual methods to the QObject class:

    virtual void LoadFromStream( QDataStream &/ST/ ) {};
    virtual void SaveToStream( QDataStream &/ST/ ) {};

    There are numerous examples in my program "Shrila Prabhupada's Dictionary"- https://github.com/Navadvipa-Chandra-das/PrabhupadaDictionaryQt . It's not quite finished yet, but it absolutely does not prevent me from demonstrating the things that I want to offer you to use!

    The point is what? Let's say we have a descendant object of the QObject class. We configured it at will, then saved it either in memory, or on a hard disk file, or in a database - to choose from. Now we can destroy the object. Then we create a new object and read its state very, very simply - with one function call! I know that there is already a QSettings class to save settings in Qt. I suggest a Storage class with similar functionality, but still there are differences between them.

    Disadvantages of QStorage:

    1. When changing the structure of settings, all previous settings are subject to deletion. This happens when updating versions of the program.
    2. It is quite difficult to edit the settings using external programs, such as a text editor and a database manager.

    Disadvantages of QSettings :

    1. Can work only with files
    2. Stores all data in text format, event binary data.
    3. Requires to create a unique string key for each portion of settings.
    4. These disadvantages lead to slower loading and saving of settings. Moreover, as the size of the ini file grows, the speed of key-value search will fall all the time.

    Advantages of QStorage:

    1. Better performance.
    2. No need to compose unique string key names for portions of settings.
    3. The ability to choose the storage location of settings - File, DB, Memory.

    Of course, I would like to see these changes in future versions of Qt, so that QStorage classes and other necessary changes appear there. I haven't implemented this class as a library yet, but only as a local class in my program, but I want to do it, and knowledge of how to create libraries in Qt is not enough yet.

    Thany You!

    With best regards, Navadvipa Chandra das.

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #2

    @Navadvipa-Chandra-das
    Hi. This is a user forum --- users of Qt just like yourself. If you wish to suggest an "improvement" to Qt nothing will happen from here. You need to report it as a bug/suggestion over at https://bugreports.qt.io/, or perhaps the developers' mailing list.

    N 1 Reply Last reply
    0
    • JonBJ JonB

      @Navadvipa-Chandra-das
      Hi. This is a user forum --- users of Qt just like yourself. If you wish to suggest an "improvement" to Qt nothing will happen from here. You need to report it as a bug/suggestion over at https://bugreports.qt.io/, or perhaps the developers' mailing list.

      N Offline
      N Offline
      Navadvipa Chandra das
      wrote on last edited by
      #3

      Hello Jon and All! Thank You!
      With best regards, Navadvipa Chandra das.

      M 1 Reply Last reply
      0
      • N Navadvipa Chandra das

        Hello Jon and All! Thank You!
        With best regards, Navadvipa Chandra das.

        M Offline
        M Offline
        mpergand
        wrote on last edited by
        #4

        Hi @Navadvipa-Chandra-das

        I have implemented the exact same thing:

        struct ArchiverInterface
        {
        	virtual void archiveWithStream(QDataStream& stream) const =0;
        	virtual bool unArchiveWithStream(QDataStream& stream)=0;
        };
        
        }
        

        and an Archiver class to deal with.
        In fact, it is a clone of the NSArchiver concept in Cocoa on Mac.
        There was a discussion about this subject here:
        https://forum.qt.io/topic/132485/how-to-save-and-load-a-qt-window-to-file?_=1690465618760

        N 1 Reply Last reply
        1
        • M mpergand

          Hi @Navadvipa-Chandra-das

          I have implemented the exact same thing:

          struct ArchiverInterface
          {
          	virtual void archiveWithStream(QDataStream& stream) const =0;
          	virtual bool unArchiveWithStream(QDataStream& stream)=0;
          };
          
          }
          

          and an Archiver class to deal with.
          In fact, it is a clone of the NSArchiver concept in Cocoa on Mac.
          There was a discussion about this subject here:
          https://forum.qt.io/topic/132485/how-to-save-and-load-a-qt-window-to-file?_=1690465618760

          N Offline
          N Offline
          Navadvipa Chandra das
          wrote on last edited by
          #5

          Hello @mpergand! Hello All!
          Thanks!
          I have created a special request-offer. Let's hope that the ice will move!
          https://bugreports.qt.io/browse/QTBUG-115571
          With best regards, Navadvipa Chandra das.

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by
            #6

            Keep in mind that adding any virtual methods to QObject would destroy binary compatibility of pretty much entire library, so anything like that won't happen before Qt7.

            Also, this adds serialization functionality to a fundamental class, that most of the time doesn't need it. It would have to provide at least the base implementation of serializing QObject itself, and handle versioning. It's a feature bloat, so I don't see it being added in the form you suggested. This should be, if at all, handled by external class of which sole purpose is serialization, so conceptually instead of object.loadFromStream(stream) something like QObjectSerializer(object).loadFromStream(stream).

            N 1 Reply Last reply
            3
            • Chris KawaC Chris Kawa

              Keep in mind that adding any virtual methods to QObject would destroy binary compatibility of pretty much entire library, so anything like that won't happen before Qt7.

              Also, this adds serialization functionality to a fundamental class, that most of the time doesn't need it. It would have to provide at least the base implementation of serializing QObject itself, and handle versioning. It's a feature bloat, so I don't see it being added in the form you suggested. This should be, if at all, handled by external class of which sole purpose is serialization, so conceptually instead of object.loadFromStream(stream) something like QObjectSerializer(object).loadFromStream(stream).

              N Offline
              N Offline
              Navadvipa Chandra das
              wrote on last edited by
              #7

              Hello Chris and All!
              I didn't even think about binary compatibility!
              If I understood you correctly, then the Storage class should not serve all QObjects, but only a select few who are heirs of the QObjectSerializer. Well, it's not difficult to fix it. In this case,

              class QStorageMainWindow : virtual public QMainWindow virtual public QObjectSerializer
              

              . We need to try whether the compiler will agree. In any case, if each object can be serialized, it seems to me not bad. The size of the VTable is increasing, but I have no idea how this will affect the performance of Qt.
              Thank you very much for the answer!
              With best regards, Navadvipa Chandra das.

              Chris KawaC 1 Reply Last reply
              0
              • N Navadvipa Chandra das

                Hello Chris and All!
                I didn't even think about binary compatibility!
                If I understood you correctly, then the Storage class should not serve all QObjects, but only a select few who are heirs of the QObjectSerializer. Well, it's not difficult to fix it. In this case,

                class QStorageMainWindow : virtual public QMainWindow virtual public QObjectSerializer
                

                . We need to try whether the compiler will agree. In any case, if each object can be serialized, it seems to me not bad. The size of the VTable is increasing, but I have no idea how this will affect the performance of Qt.
                Thank you very much for the answer!
                With best regards, Navadvipa Chandra das.

                Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by Chris Kawa
                #8

                @Navadvipa-Chandra-das:

                If I understood you correctly, then the Storage class should not serve all QObjects, but only a select few who are heirs of the QObjectSerializer

                No, that's not what I meant. It wouldn't be of much use if it only supported selected classes inheriting from something.

                class QStorageMainWindow : virtual public QMainWindow virtual public QObjectSerializer

                That's still the same issue as before, just shifted up in the class hierarchy.

                What I'm saying is serialization should not be part of a class that is being serialized. That's mixing concerns. Imagine you have 50 existing classes in your app and then want to serialize them - with your approach you have to modify code of 50 existing classes! That's not a good design.

                What I'm suggesting is more like this (and keep in mind this is just loose idea, not a concrete implementation):

                class MyClass {  /* Knows nothing about serialization */ };
                
                // Interface for serialization
                class ISerializer
                {
                   virtual void serialize(QObject* obj, QDataStream& stream) = 0;
                   virtual void deserialize(QObject* obj, QDataStream& stream) = 0;
                }
                
                // Implementation for MyClass
                class MyClassSerializer : public ISerializer
                {
                   void serialize(QObject* obj, QDataStream& stream) override { ... };
                   void deserialize(QObject* obj, QDataStream& stream) override { ... };
                }
                

                Then you'd register this particular serializer for the specific meta type of that class. Could be a static method on the QObjectSerializer or some automatic way, but in any case the constructor QObjectSerializer(object) would look up the registered serializer for that specific type and use it. If it couldn't find serializer for the specific type it could go up the inheritance chain via meta object lookup and look for serializers for base classes, until it reached the QObject. A serializer for that could e.g. go through all Q_PROPERTies and serialize those.

                Adding support for new types would be noninvasive - it's just adding new serializer classes without touching the original classes or the QObjectSerializer. That's cleanly extendible and binary compatible.

                N 1 Reply Last reply
                3
                • Chris KawaC Chris Kawa

                  @Navadvipa-Chandra-das:

                  If I understood you correctly, then the Storage class should not serve all QObjects, but only a select few who are heirs of the QObjectSerializer

                  No, that's not what I meant. It wouldn't be of much use if it only supported selected classes inheriting from something.

                  class QStorageMainWindow : virtual public QMainWindow virtual public QObjectSerializer

                  That's still the same issue as before, just shifted up in the class hierarchy.

                  What I'm saying is serialization should not be part of a class that is being serialized. That's mixing concerns. Imagine you have 50 existing classes in your app and then want to serialize them - with your approach you have to modify code of 50 existing classes! That's not a good design.

                  What I'm suggesting is more like this (and keep in mind this is just loose idea, not a concrete implementation):

                  class MyClass {  /* Knows nothing about serialization */ };
                  
                  // Interface for serialization
                  class ISerializer
                  {
                     virtual void serialize(QObject* obj, QDataStream& stream) = 0;
                     virtual void deserialize(QObject* obj, QDataStream& stream) = 0;
                  }
                  
                  // Implementation for MyClass
                  class MyClassSerializer : public ISerializer
                  {
                     void serialize(QObject* obj, QDataStream& stream) override { ... };
                     void deserialize(QObject* obj, QDataStream& stream) override { ... };
                  }
                  

                  Then you'd register this particular serializer for the specific meta type of that class. Could be a static method on the QObjectSerializer or some automatic way, but in any case the constructor QObjectSerializer(object) would look up the registered serializer for that specific type and use it. If it couldn't find serializer for the specific type it could go up the inheritance chain via meta object lookup and look for serializers for base classes, until it reached the QObject. A serializer for that could e.g. go through all Q_PROPERTies and serialize those.

                  Adding support for new types would be noninvasive - it's just adding new serializer classes without touching the original classes or the QObjectSerializer. That's cleanly extendible and binary compatible.

                  N Offline
                  N Offline
                  Navadvipa Chandra das
                  wrote on last edited by
                  #9

                  Hello Chris and All!
                  I understood. Thanks! I agree that for version 6 of Qt it is better to have separate classes for serialization for binary compatibility. But for the seventh version of Qt - I do not agree. As a user, I want to be provided with a full-fledged class that can serialize itself. For example, when buying a car, I want the first-aid kit to be put inside the car, and not told that here is a car for you, and you will carry the first-aid kit on a special cart. In addition, you can not change the code of all 50 classes, but simply make 50 heirs. In this case, the parity is 50 heirs against 50 serializer classes. In addition, these 50 serializer classes will have to repeat the hierarchical tree of heirs, which in itself is tedious. And when the hierarchy of these 50 classes changes, then the tree of the 50 serializer classes will have to change, hurrying after them. It is a very tedious, thankless task to synchronize disparate pieces of code. In addition, this is a clear overspending of both memory and processor time. In any case - I can't make any decision - it will be made by other people. I remember there were object databases for C++ and C#. For C#, one such was once called FastObject. The bottom line is that any object can be saved in the database! They even had a slogan: "Stop thinking square!" Although they were based on quite a square idea - a table of pairs - key and value.
                  Thank you very much!
                  With best regards, Navadvipa Chandra das.

                  Chris KawaC 1 Reply Last reply
                  0
                  • N Navadvipa Chandra das

                    Hello Chris and All!
                    I understood. Thanks! I agree that for version 6 of Qt it is better to have separate classes for serialization for binary compatibility. But for the seventh version of Qt - I do not agree. As a user, I want to be provided with a full-fledged class that can serialize itself. For example, when buying a car, I want the first-aid kit to be put inside the car, and not told that here is a car for you, and you will carry the first-aid kit on a special cart. In addition, you can not change the code of all 50 classes, but simply make 50 heirs. In this case, the parity is 50 heirs against 50 serializer classes. In addition, these 50 serializer classes will have to repeat the hierarchical tree of heirs, which in itself is tedious. And when the hierarchy of these 50 classes changes, then the tree of the 50 serializer classes will have to change, hurrying after them. It is a very tedious, thankless task to synchronize disparate pieces of code. In addition, this is a clear overspending of both memory and processor time. In any case - I can't make any decision - it will be made by other people. I remember there were object databases for C++ and C#. For C#, one such was once called FastObject. The bottom line is that any object can be saved in the database! They even had a slogan: "Stop thinking square!" Although they were based on quite a square idea - a table of pairs - key and value.
                    Thank you very much!
                    With best regards, Navadvipa Chandra das.

                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #10

                    @Navadvipa-Chandra-das As a counter-argument - I'm another user that has absolutely no use for such a functionality. I don't use databases. I don't serialize my QObjects. I have large number of classes that I want to keep as slim as possible due to memory constraints. Why do I have to pay in every single one of my QObject derived classes for a feature that you need? And if you need serialization and you want to stuff it in every class then I might want my feature there too, and someone else might want another... Someone might wan thread safety and a mutex in every method. Someone might want network replication that drags more dependencies in. Someone might want a printable version of objects for logging and debug purposes. This is a straight way to bloat on a class that is fundamental and already quite heavy. IMO in such large frameworks fundamental base objects should be as slim as possible and provide only the absolute minimum of functionalities.

                    N 2 Replies Last reply
                    2
                    • Chris KawaC Chris Kawa

                      @Navadvipa-Chandra-das As a counter-argument - I'm another user that has absolutely no use for such a functionality. I don't use databases. I don't serialize my QObjects. I have large number of classes that I want to keep as slim as possible due to memory constraints. Why do I have to pay in every single one of my QObject derived classes for a feature that you need? And if you need serialization and you want to stuff it in every class then I might want my feature there too, and someone else might want another... Someone might wan thread safety and a mutex in every method. Someone might want network replication that drags more dependencies in. Someone might want a printable version of objects for logging and debug purposes. This is a straight way to bloat on a class that is fundamental and already quite heavy. IMO in such large frameworks fundamental base objects should be as slim as possible and provide only the absolute minimum of functionalities.

                      N Offline
                      N Offline
                      Navadvipa Chandra das
                      wrote on last edited by Navadvipa Chandra das
                      #11

                      Hello, Chris Kawa and All!
                      Well, I agree. Except that the LoadFromStream( QDataStream& ) and SaveToStream( QDataStream& ) functions themselves do not require a database. Databases already require the Storage class, so it can be moved to a separate library.

                      class ISerializer : public QObject
                      {
                        public:
                        static std::map< QMetaObject*, QMetaObject* > m_Map;
                        static void Register( QMetaObject* AObject, QMetaObject* ASerializer );
                        public slots:
                         virtual void LoadFromStream( QObject* obj, QDataStream& stream) = 0;
                         virtual void SaveToStream( QObject* obj, QDataStream& stream) = 0;
                      
                      

                      ISerializer must be inherited from QOject in order to have the QMetaObject* metaObject() function. I haven't tried compiling anything yet, I'm just guessing. public slots: I think it is necessary for invokeMethod to work.

                      Then you need to do something like:

                      QMetaObject::invokeMethod( AObject
                      , "LoadFromStream"
                      , Qt::DirectConnection
                      , AStream );

                      Is this supposed to work? I will try!

                      Thank You!
                      With best regards, Navadvipa Chandra das.

                      N 1 Reply Last reply
                      0
                      • N Navadvipa Chandra das

                        Hello, Chris Kawa and All!
                        Well, I agree. Except that the LoadFromStream( QDataStream& ) and SaveToStream( QDataStream& ) functions themselves do not require a database. Databases already require the Storage class, so it can be moved to a separate library.

                        class ISerializer : public QObject
                        {
                          public:
                          static std::map< QMetaObject*, QMetaObject* > m_Map;
                          static void Register( QMetaObject* AObject, QMetaObject* ASerializer );
                          public slots:
                           virtual void LoadFromStream( QObject* obj, QDataStream& stream) = 0;
                           virtual void SaveToStream( QObject* obj, QDataStream& stream) = 0;
                        
                        

                        ISerializer must be inherited from QOject in order to have the QMetaObject* metaObject() function. I haven't tried compiling anything yet, I'm just guessing. public slots: I think it is necessary for invokeMethod to work.

                        Then you need to do something like:

                        QMetaObject::invokeMethod( AObject
                        , "LoadFromStream"
                        , Qt::DirectConnection
                        , AStream );

                        Is this supposed to work? I will try!

                        Thank You!
                        With best regards, Navadvipa Chandra das.

                        N Offline
                        N Offline
                        Navadvipa Chandra das
                        wrote on last edited by
                        #12
                        This post is deleted!
                        1 Reply Last reply
                        0
                        • Chris KawaC Chris Kawa

                          @Navadvipa-Chandra-das As a counter-argument - I'm another user that has absolutely no use for such a functionality. I don't use databases. I don't serialize my QObjects. I have large number of classes that I want to keep as slim as possible due to memory constraints. Why do I have to pay in every single one of my QObject derived classes for a feature that you need? And if you need serialization and you want to stuff it in every class then I might want my feature there too, and someone else might want another... Someone might wan thread safety and a mutex in every method. Someone might want network replication that drags more dependencies in. Someone might want a printable version of objects for logging and debug purposes. This is a straight way to bloat on a class that is fundamental and already quite heavy. IMO in such large frameworks fundamental base objects should be as slim as possible and provide only the absolute minimum of functionalities.

                          N Offline
                          N Offline
                          Navadvipa Chandra das
                          wrote on last edited by
                          #13

                          Hello, Chris Kawa and All!

                          Thiago Macieira from Qt teams gave me the idea to use Qt metadata instead of a virtual function in class QObject! Now there is binary compatibility with Qt!

                          https://github.com/Navadvipa-Chandra-das/PrabhupadaDictionaryQt
                          The main change is that two virtual functions in the QObject base class have been removed! Now, the class that wants to be saved and restored using the Storage class must make two slots:

                            public slots:
                              void LoadFromStream( QDataStream &ST );
                              void SaveToStream( QDataStream &ST );
                          

                          Meta-information is not inherited, and each class must still make these two slots, even if they will just call the ancestor method without adding any new code! But you can build an inheritance hierarchy and it works well. Probably the call is a little slower than calling a virtual function, but not the QObject class remains as fast as possible!

                          That's what happened:

                          O->LoadFromStream( *m_Stream );
                          

                          And here's what happened now:

                          InvokeSuccess = QMetaObject::invokeMethod( O, "LoadFromStream", Q_ARG( QDataStream&, *m_Stream ) );
                          

                          Now let's see what the Qt team says! Interesting!
                          Thank You!

                          With best regards, Navadvipa Chandra dasa.

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved