Returning C++ references from more programming interfaces?



  • I suggest to take another look at a known software situation:
    The class “QStandardItem” provides a programming interface for a two-dimensional table while the class “QVector” provides a programming interface for a one-dimensional data structure.

    I find it interesting then that the QVector class contains some member functions which return references to an object which was stored at a specific position in such a container. Can this functionality make sense also for other classes like QStandardItem?


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    I find it interesting then that the QVector class contains some member functions which return references to an object which was stored at a specific position in such a container. Can this functionality make sense also for other classes like QStandardItem?

    No, it does not make sense.

    If you add this functionality to QStandardItem, you will break encapsulation which is bad for object-oriented programming.



  • …, you will break encapsulation which is bad for object-oriented programming.

    Do you find the “encapsulation” already broken for the QVector class then?

    Will software design extensions become feasible?


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    Do you find the “encapsulation” already broken for the QVector class then?

    No, because QVector is a generic container. It is designed to allow full access to every element.

    QStandardItem is not a generic container.



  • QStandardItem is not a generic container.

    Can any more generic functionality be combined also with this class?


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    Can any more generic functionality be combined also with this class?

    No. QStandardItem is a very specific class so you should not add generic functionality to it.

    If you want generic functionality, use a different class.



  • Say you return a reference (to the data, I assume). And you change said data. How is the model supposed to know that the data changed. In other words, who takes care of emitting dataChanged()?
    The reference user can't be an acceptable answer as it would mean the developer has to remember to call a function every time and that's not something the current C++ evolution likes.



  • In other words, who takes care of emitting dataChanged()?

    The responsibility is the same to notify others about data changes, isn't it?

    Have you got the impression that this aspect would be different because of the reachability of specific information by pointers or references?


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    In other words, who takes care of emitting dataChanged()?

    The responsibility is the same to notify others about data changes, isn't it?

    Have you got the impression that this aspect would be different because of the reachability of specific information by pointers or references?

    QStandardItemModel is responsible for emitting dataChanged(). Every time you call QStandardItem::setValue(), QStandardItemModel will automatically emit dataChanged().

    If you get a reference to the QStandardItem's data and then modify the data, the dataChanged() signal will not be emitted. This is why we MUST NOT provide a reference to a QStandardItem's data!



  • Every time you call QStandardItem::setValue(), …

    Would you like to refer to an other class (or member function) here?

    If you get a reference to the QStandardItem's data and then modify the data, the dataChanged() signal will not be emitted.

    How do you think about to take additional solutions into account for this software development concern?

    Can such customised functions trigger also the desired change notification?



  • @elfring said in Returning C++ references from more programming interfaces?:

    Would you like to refer to an other class (or member function) here?

    It's setData, just a typo

    Can such customised functions trigger also the desired change notification?

    I can't think of how but I'm happy to see an example implementation of what would work



  • I can't think of how but I'm happy to see an example implementation of what would work

    I am curious on how the corresponding change acceptance will evolve for possible extensions around the class “QStandardItem”.


  • Moderators

    @elfring I think @VRonin asked for an example, you do not have to submit a patch to Qt



  • … , you do not have to submit a patch to Qt

    • Can the work with elements from a QStandardItem object become as convenient as the access for simple arrays?
    • Are you used to the programming with template functions and overloaded operators?


  • To put it into prospective, let's assume we have something like this and let's assume int is not super cheap to copy, just for argument sake:

    class Example : public QObject{
        Q_OBJECT
    public:
        explicit Example(QObject* parent = nullptr) 
            : QObject(parent), m_value(0)
        {}
        const int& value() const {return m_value;}
        void setValue(const int& val){
            if(m_value==val)
                return;
            m_value=val;
            valueChanged(m_value);
        }
    signals:
        void valueChanged(int val);
    private:
        int m_value;
    };
    

    How would you structure something like int& value() {return m_value;} that assures you the signal valueChanged is emitted in case the reference is changed?



  • How would you structure something like …

    I would expect that the member variable will be changed only if no C++ exceptions were thrown.
    Thus I would interpret the following approach as an useful software design option.

    void modify(my_data const & md)
    {
    m_value = md;
    emit valueChanged();
    }
    

    Would you like to extend such an example with function objects or the application of lambdas?



  • m_value = md;

    So what's the advantage of using a reference if you still call the assignment operator (that would trigger a copy)? and what's the difference between your modify and my setValue?



  • … and what's the difference between your modify and my setValue?

    I omitted an equality check in my example.
    But I guess that this implementation detail distracts from the original issue of my feature request here.

    Would you like to adjust programming interfaces around container class variants any further?



  • You didn't answer

    @VRonin said in Returning C++ references from more programming interfaces?:

    How would you structure something like int& value() {return m_value;} that assures you the signal valueChanged is emitted in case the reference is changed?



  • You didn't answer

    I suggest to distinguish the update scope and the actor which should trigger the desired change notification (by a specific function call).
    Another software design option would be the use of a corresponding class, wouldn't it?

    Example demo1;
    
    struct notifier
    {
     Example& ex;
     
     notifier(Example& target, int input)
     : ex(target)
     { ex[0] = input; }
     
     ~notifier()
     { ex.valueChanged(); }
    } demo2(demo1, 123);
    

  • Moderators

    @elfring, so you want programmers to replace Code 1 with Code 2; have I understood you correctly?

    //======
    // Code 1
    //======
    Example demo1;
    demo1.setData(123); // Automatically emits valueChanged() immediately
    
    //======
    // Code 2
    //======
    Example demo1;
    notifier demo2(demo1, 123);
    
    // valueChanged() is emitted when demo2 is destroyed
    

    I must say that Code 1 is a much more elegant and intuitive than Code 2.



  • so you want programmers to replace Code 1 with Code 2; …

    Not really. - I suggest to choose between available software design options.

    The standard behaviour of the function “QStandardItem::setData” is generally fine.
    The software situaton might look different if more reference-returning functions from a container class like QVector will be taken into account.
    A need can evolve to call the function “valueChanged” (or “dataChanged”) in a C++ destructor, can't it?


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    so you want programmers to replace Code 1 with Code 2; …

    Not really. - I suggest to choose between available software design options.

    OK.

    The standard behaviour of the function “QStandardItem::setData” is generally fine.

    I'm glad you think it's generally fine.

    The software situaton might look different if more reference-returning functions from a container class like QVector will be taken into account.

    I already explained above why QStandardItem must not provide a reference to is internal data. Do you understand that explanation?

    A need can evolve to call the function “valueChanged” (or “dataChanged”) in a C++ destructor, can't it?

    No, it can't. The signal should be emitted immediately when the data is changed. It should not wait for the destructor of another struct/object.



  • Do you understand that explanation?

    I can follow software development concerns (which were expressed here) to some degree.

    The signal should be emitted immediately when the data is changed.

    This expectation is also generally fine.

    It should not wait for the destructor of another struct/object.

    The available programming interfaces support to call desired functions in C++ destructors. You can choose under which circumstances such a software design approach will be appropriate.


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    I can follow software development concerns (which were expressed here) to some degree.

    That's good. So please address those concerns. For example, why should Qt provide extensions that break encapsulation and increase the risk of errors?

    The signal should be emitted immediately when the data is changed.

    This expectation is also generally fine.

    Good.

    It should not wait for the destructor of another struct/object.

    The available programming interfaces support to call desired functions in C++ destructors. You can choose under which circumstances such a software design approach will be appropriate.

    I cannot see any circumstance where such a software design approach will be appropriate.



  • For example, why should Qt provide extensions that break encapsulation and increase the risk of errors?

    I suggest to use algorithms which can work together with container classes at more source code places.


  • Moderators

    @elfring said in Returning C++ references from more programming interfaces?:

    For example, why should Qt provide extensions that break encapsulation and increase the risk of errors?

    I suggest to use algorithms which can work together with container classes at more source code places.

    You did not address any of the concerns. You only added suggestions.

    That is not acceptable. You must only submit ideas/proposals that don't break encapsulation.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.