What about little help with signals and slots checking?



  • When I first started use Qt at end of 90th - I used it "as it is". If docs say: to generate signal name in connect() I must use SIGNAL() macro - then I use it. But I always asked myself - why not developers change this simple macro to something more powerful? O-key... They are very busy with other not developed yet parts. While project grows - then there are more and more parts to develope. Good working old solutions stay unchanged for years. And I told myself - they will make something better in future. Just wait...

    The future came but this macro still used to generate signal (and SLOT() for slot) name to do connection. I don't tell this macro is bad - but it is not the best. Look at that: if you make mistake in method name or if you changed it's parameters type but forgot change them in each place where you connect this method - then connection won't work. It is needed in code check connections each time to be sure.

    Why MOC cannot do that check?

    Why not just extend MOC language and functionality with simple addition - key words for signal and slot name generation? For example

    connect( signal class1 this method1, slot class2 other method2 );

    What does this mean?
    signal - new keyword for MOC showing that we generate name of signal
    class1 - new refer to class1 where method1(int) must be defined as signal
    this - pointer to object with class1
    slot - new keyword for MOC showing that we generate name of slot
    other - pointer to object with class2
    class2 - new refer to class2 where method2(int) must be defined as slot

    Then MOC when meets these extensions - it just performs checking of existence method1 in class1 and it's definition as signal. Same for slot method2 in class2. Notice that parameters of methods are omited - MOC can take them from declarations of these methods. For example they are both int. Then MOC checks if method1 can be connected to method2. And if all is OK then MOC just changes this to

    connect( (class1*) this, SIGNAL(method1(int)), (class2*) other, SLOT(method2(int)) );

    for conventional preprocessor. But if the signal does not match slot - MOC prints error.

    Sorry if this idea is not new (it MUST be not new...) and already discussed. I cannot read all Qt-related discussions... 10 years ago Qt was tool "for those who knows". But I believe it will grow and be more and more popular. This addition will make it's usage more useful.

    (for those who used words slot and signal in their projects - keywords can be other, here I talk about idea)





  • Oh my... This looks complicated and not useful. And breaks compatability!

    I just suggest force MOC do check job and extend new keywords as it did in class declarations. Very small additions and clear syntax...

    Amd I did not get - will new (Qt5) syntax work in static initialization of signal/slot names?

    In case like this:

    @typedef struct {
    const char* name;
    const char* method;
    bool signal;
    Qt::ConnectionType type;
    bool autoconnect;
    } SOCKETINFO;

    static SOCKETINFO socketz[] = {
    { "Output-1", SIGNAL(measuredValue( float )), true, Qt::AutoConnection, true },
    { "Input-1", SLOT(activateMeasure( int )), false, Qt::AutoConnection }
    };@

    Will it work?

    In my suggestion - it can work. Just with the code

    @static SOCKETINFO socketz[] = {
    { "Output-1", signal class1 method1, true, Qt::AutoConnection, true },
    { "Input-1", slot class1 method2, false, Qt::AutoConnection }
    };@

    MOC avoids checking connection possibility (there is no object pointer and second class name). It just checks if the method1 is a signal in class1 (and method2 is a slot). If ok it generates previous code. All good old code in Qt will work.

    My idea can work with Qt4. Even with all previous projects - only new MOC needed.



  • I'm not saying your approach is bad, but I have a few points to make:
    [quote]
    if you make mistake in method name
    [/quote]
    How is that going to be different in your approach? (Because it's done at compile time?)

    [quote]
    Then MOC when meets these extensions – it just performs checking of existence method1 in class1 and it’s definition as signal. Same for slot method2 in class2. Notice that parameters of methods are omited – MOC can take them from declarations of these methods. For example they are both int. Then MOC checks if method1 can be connected to method2. And if all is OK then MOC just changes this to
    [/quote]
    There is a similar problem to the implementation suggested for Qt5. How does the MOC know which signal to use if there are multiple overloaded signals? Maybe even though the data types are the same, the information they carry is not.

    And about your example:
    @static SOCKETINFO socketz[] = {
    { "Output-1", signal class1 method1, true, Qt::AutoConnection, true },
    { "Input-1", slot class1 method2, false, Qt::AutoConnection }
    };@
    If there method 1 is overloaded how does the MOC know which method to use (the connection isn't done until later. This also holds generally. The MOC would need to check if you are within the scope of a QObject connect to perform the type matching. What if you want to write a custom method that you need to pass a signal/slot. What if you (hypothetically) override connect and it is somehow different. How is the MOC going to detect all that?



  • bq. Oh my… This looks complicated.
    I just suggest force MOC do check job and extend new keywords as it did in class declarations. Very small additions and clear syntax…

    On the contrary, the syntax though complex is actually following the new industry standards in C++, similar syntax is used in another popular C++ library "Boost" too, and is trying to be in sync with the C++ standards committee. So as a standard, it makes it easier for coders to recognize and understand it. It also provides compile-time checking.. not to mention inlines in C++0x and many small neat things. So it's all good!



  • Yes, and it's probably also going to improve performance (hopefully), because the compiler can make better optimizations.



  • bq. How does the MOC know which signal to use if there are multiple overloaded signals?

    if there is more than one matching pair - it can break with error, then syntax can allow parameter type names after method name

    bq. If there method 1 is overloaded how does the MOC know which method to use

    answer is the same - error message with ability add type names

    @static SOCKETINFO socketz[] = {
    { "Output-1", signal class1 method1 int, float, Qt::AutoConnection, true },
    { "Input-1", slot class1 method2, false, Qt::AutoConnection }
    };@

    if there are method1(int) and method1(int,float) then error message again - you have point type names completely to not confuse MOC

    in connection it can be done once:

    @connect( signal class1 this method1 int float, slot class2 other method2 );

    that means error if method2(int,float) is not declared in class2



  • bq. So as a standard, it makes it easier for coders to recognize and understand it. It also provides compile-time checking..

    but it breaks compatibility with previous apps on the root... Will old-style connection work in Qt5?



  • If you are seriously aware about "syntax standard" - it can be:

    @static SOCKETINFO socketz[] = {
    { "Output-1", signal class1::method1( int, true ), Qt::AutoConnection, true },
    { "Input-1", slot class1 method2, false, Qt::AutoConnection }
    };@
    and

    @connect( signal (class1)this::method1( int, float ), slot (class2) other::method2 );@

    but the idea assumes it is compatible to already created applications


  • Moderators

    The new syntax is supposed to be an addition to the existing one. At least that is what was said at QtCS.



  • That's good. That means my suggestion does not intersect with new syntax. They can exist both. MOC additions should be made only by MOC developer(s) and only in MOC. It could appear for Qt4 and be further used in Qt5. Programmer will choose what is better for him.


  • Moderators

    I wonder what a C++ compiler does with your syntax. To me it looks like it will consider the connect statement a syntax error and bail out. The compiler needs to parse the code as well as moc.



  • bq. I wonder what a C++ compiler does with your syntax.

    The C++ compiler must not see that! After MOC it should be the conventional C++ syntax with present SIGNAL() and SLOT() macros!

    @static SOCKETINFO socketz[] = {
    { "Output-1", signal class1::method1( int, true ), Qt::AutoConnection, true },
    { "Input-1", slot class1::method2, false, Qt::AutoConnection }
    };@
    MOC shout turn to
    @static SOCKETINFO socketz[] = {
    { "Output-1", SIGNAL(measuredValue( float )), true, Qt::AutoConnection, true },
    { "Input-1", SLOT(activateMeasure( int )), false, Qt::AutoConnection }
    };@

    and
    @connect( signal (class1)this::method1( int, float ), slot (class2)other::method2 );@
    to
    @connect( (class1)this, SIGNAL(method1( int, float )), (class2)other, SLOT(method2( int, float )) );@
    but if only matching method2( int, float ) declared in class2



  • The MOC cannot modify your files.



  • The point is, MOC does create source code and is no pre processor for the c++ compiler. so C++ compiler would see

    @
    connect( signal (class1)this::method1( int, float ), slot (class2)other::method2 );
    @

    which can't be simply mapped with #defines.

    @
    connect( this, SIGNAL(method1( int, float )), other, SLOT(method2( int, float )) );
    @

    will be expanded by the pre processor to

    @
    QObject::connect(this, "1method1( int, float )", other, "2method2( int, float )");
    @

    Using this method, you can event connect QObject pointers without knowing the real implementation class. With your syntax it is mandatory to know them inside the class doing the connect, which means connect on QObject pointer is only possible for QObject slots/signals.

    On the other side, the new sysntax is not complex, it's just C++ standard (pointer to member) and STL. This is nice, as this is also standard.



  • But MOC could work like preprocessor.



  • Well yes, but as Gerolf pointed out, the MOC is not preprocessor, so the compiler will till see your syntax in the cpp file.



  • No, MOC can't work as pre provcessor. This would mean to modify the build chain, as pre processor creates an intermediate file used by the processor. If moc should work as pre processor, it must create the first intermediate file, which is then processed by the pre processor of the used build chain, which also means to modify the make file syntax to something, noone will understand.

    It makes no sense from my POV.



  • Hm... are there still any people who looks at automatically generated makefiles?... :-D

    BTW I still did not get - will new Qt5 syntax and checking work for statically initialized pointers to signals/slots?



  • [quote author="Gourmand" date="1308685686"]Hm... are there still any people who looks at automatically generated makefiles?... :-D[/quote]
    That would be me.

    The thing that really worries me about the new syntax is the fact that encapsulation is broken. That isn't all that good from my point of view. Signals and slots traditionally helped in decoupling and encapsulation. It would be a shame to throw that away to support a new syntax that only has local advantages. I do like the non-blocking open file example, but if it means breaking a lot of goodness, I rather write a slot or two instead.

    Overloading of slots is probably going to be discouraged according to the doc, which is rather useless if you want to keep the "normal class function with added calling possibilities".



  • If I understood correctly, old and new syntax should work, so that would mean, old stuff will go on working, and decoupling also.



  • [quote author="Gerolf" date="1308722120"]If I understood correctly, old and new syntax should work, so that would mean, old stuff will go on working, and decoupling also.[/quote]
    True that. The encapsulation is achieved by keeping the signals protected, which has to be changed for the new syntax to work. To be honest, that still sounds like a deal-breaker to me.



  • I agree with Franzk on the worry about breaking encapsulation (especially the example about having a public aboutToQuit signal which can then called/emitted from another class!). But i'm positive, they will find a solution for that.



  • Encapsulation is already broken with signals and slots. I don't see how making the signals public will break it more than it already is. Even now, you can use this to trigger a signal in another object:

    @
    QMetaObject::invokeMethod(theOtherObject, "myDangerousSignal", Q_ARG(bool, m_selfDestruct));
    @

    Making the signal public will make the above a bit easier, but the effect won't be any different:
    @
    theOtherObject->myDangerousSignal(m_selfDestruct);
    @

    Same goes for slots, by the way. They are open to the public if a user really wants to, even the ones you declared as private.

    Bottom line for me: there needs to be careful consideration if making the signals public is worth the benefit. Making them public may send the wrong message in terms of API design, but the actual protection of the methods does not change. That makes it, in my eyes, not a deal-braker if the benefits are great enough.



  • I agree too it's not a deal breaker.. but it is a concern that needs to be addressed. While using the

    @ QMetaObject::invokeMethod(myObject, mySignal) @

    It is a level of abstraction and it's clear when we want to script the object and make it emit some signal. The normal legal way being the

    @ emit mySignal(); @

    Which of course cannot be done by classes other than the owner.

    But bringing that to the level of a C++ method call is breaking encapsulation.. the goal being to prevent such dangerous access to the class.



  • There is a big difference between having to type
    @QMetaObject::invokeMethod(theOtherObject, "myDangerousSignal", Q_ARG(bool, m_selfDestruct));@
    and just being able to type
    @theOtherObject->myDangerousSignal(m_selfDestruct);@
    and get away with it because the signal is considered public by the compiler

    Edit: Improved sentence.



  • I think the thread went a bit off topic when dealing with Qt5 overloads for connect() accepting lambdas, pointer to members etc.

    bq. Why MOC cannot do that check?

    What you suggest is doable, but moc IMHO is the wrong place to do that. Instead, you should move the logic into the compiler itself, and have it check at compile time (whenever it's possible) that the specified signals and slots in the connect() statement DO exist in the respective classes. For instance, you could write a gcc plugin (in Python) to do exactly that, and emit a warning in case the compiler finds something strange with a connect.

    Notice also that any Qt-enabled IDE (YMMV) will help you in writing the right connect statements, and refactoring the relevant code.

    bq. Then MOC when meets these extensions – it just performs checking of existence method1 in class1 and it’s definition as signal. Same for slot method2 in class2. Notice that parameters of methods are omited – MOC can take them from declarations of these methods. For example they are both int.

    What's exactly the advantage of doing that? And by the way, it's generally wrong. You can have overloads for both signals and slots, therefore more than one match can possibly exist.



  • bq. Instead, you should move the logic into the compiler itself

    no, in my idea checking must perform before preprocessing to change additional keywords to fine-tuned SIGNAL and SLOT macros

    if only it was built into preprocessor before it's main engine...

    bq. You can have overloads for both signals and slots, therefore more than one match can possibly exist.

    you just did not read forward, later I told about overloading - if this appears and processor confuses, then it just prints out an error - and extra parameters declaration solves problem

    but this all is not interesting for people here, including authors... this could be interesting only for developers who want use old connection style and have check at compile time

    bq. Notice also that any Qt-enabled IDE (YMMV) will help you

    thanx but I've already got accustomed to QtCreator


Log in to reply
 

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