Simpelster Code funktioniert nicht so wie er soll



  • warum nur schrieb:

    Wie oft noch? 🙄 Keiner braucht sie.

    Wie wärs mit einer Begründung? Es geht nicht nur darum, was du persönlich findest.

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts

    Ziemlich kreative Schlussfolgerung.

    Ich habe ja schon erwähnt, wozu Funktionsdeklarationen innerhalb anderer Funktionen nützlich sein können. Wenn man grössere .cpp-Dateien hat, kann es von Vorteil sein, selten benutzte Funktionen nicht global zu deklarieren, damit der Zugriff beschränkt und lokal gehalten werden kann. In Headerdateien kannst du mit lokalen Funktionsdeklarationen verhindern, dass Funktionen plötzlich für alle einbindenden Dateien sichtbar werden.


  • Mod

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts und sind nur inkonsistent.

    Also willst du eine Inkonsistenz durch eine andere ersetzen? Und überhaupt, ich möchte wenigstens ein Beispiel sehen, das durch die Abschaffung lokaler Funktionsdeklaration verbessert wird.



  • Nexus schrieb:

    warum nur schrieb:

    Wie oft noch? 🙄 Keiner braucht sie.

    Wie wärs mit einer Begründung? Es geht nicht nur darum, was du persönlich findest.

    Hmm, wir haben weit über 1 Millionen LOC. Ich hab noch nicht alle davon gesehen, aber schon ne ganze Menge und keine war ne lokale Funktionsdeklaration. Ich kann mich nicht erinnern in einem opensource Code eine gesehen zu haben. Keiner kann mir ein sinnvolles Beispiel zeigen. Deines ist es nicht wirklich, siehe unten.

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts

    Ziemlich kreative Schlussfolgerung.

    Ich habe ja schon erwähnt, wozu Funktionsdeklarationen innerhalb anderer Funktionen nützlich sein können. Wenn man grössere .cpp-Dateien hat, kann es von Vorteil sein, selten benutzte Funktionen nicht global zu deklarieren, damit der Zugriff beschränkt und lokal gehalten werden kann.

    Und die Definition muss dann immer ganz unten sein, damit sie sonst keiner sieht, was ziemlich dämlich ist, weil es eben keine lokalen Funktionsdefinitionen gibt. Damit funktioniert es genau für eine Funktion richtig.

    In Headerdateien kannst du mit lokalen Funktionsdeklarationen verhindern, dass Funktionen plötzlich für alle einbindenden Dateien sichtbar werden.

    Das geht mit anonymen Namespaces viel schöner, in soeinem müsstest du sowieso die Definition verstecken.

    camper schrieb:

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts und sind nur inkonsistent.

    Also willst du eine Inkonsistenz durch eine andere ersetzen?

    Welche andere?

    Und überhaupt, ich möchte wenigstens ein Beispiel sehen, das durch die Abschaffung lokaler Funktionsdeklaration verbessert wird.

    Siehe Threadanfang.



  • warum nur schrieb:

    camper schrieb:

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts und sind nur inkonsistent.

    Also willst du eine Inkonsistenz durch eine andere ersetzen?

    Welche andere?

    Du liest nicht was die anderen schreiben, oder?



  • Janjan schrieb:

    warum nur schrieb:

    camper schrieb:

    warum nur schrieb:

    Lokale Funktionsdefinitionen sind unzulässig, also bringen lokale Funktionsdeklaration sowieso nichts und sind nur inkonsistent.

    Also willst du eine Inkonsistenz durch eine andere ersetzen?

    Welche andere?

    Du liest nicht was die anderen schreiben, oder?

    Sag was du meinst?



  • run.cpp

    #include <iostream>
    using namespace std;
    
    void run()
    {
        int x = 10;
        x++;
        cout << x << endl;
    }
    

    func.h

    void doIt() {
        void run();
        run();
    }
    

    main.cpp

    #include "func.h"
    
    int main() {
        doIt();
    }
    

    Hätte man einen Header "run.h" global in func.h includiert (oder doIt selber global deklariert), könnte man in main.cpp auch direkt auch run() aufrufen. Wenn du das nicht willst machst du eine lokale Funktionsdeklaration und gut ists. Und dein doIt() bleibt immer noch inline!



  • warum nur schrieb:

    Hmm, wir haben weit über 1 Millionen LOC. Ich hab noch nicht alle davon gesehen, aber schon ne ganze Menge und keine war ne lokale Funktionsdeklaration.

    Ich habe "keiner braucht sie" so verstanden, dass sie für niemanden einen Nutzen haben. Dass sie in der Realität nicht oft eingesetzt werden, glaube ich zwar gern, aber wie viel sagt dieser Sachverhalt über die Nützlichkeit eines Features aus? Es gibt einige Sprachmittel, die in der C++-Community keine grosse Bekanntheit geniessen, ohne gleich unnütz zu sein.

    warum nur schrieb:

    Und die Definition muss dann immer ganz unten sein, damit sie sonst keiner sieht, was ziemlich dämlich ist, weil es eben keine lokalen Funktionsdefinitionen gibt. Damit funktioniert es genau für eine Funktion richtig.

    Deine Aussage trifft nur auf Funktionen zu, die in der selben Übersetzungseinheit definiert werden.

    warum nur schrieb:

    Das geht mit anonymen Namespaces viel schöner, in soeinem müsstest du sowieso die Definition verstecken.

    Nein, müsste man wiederum nicht, wenn die Funktion in einem anderen Modul definiert ist. Anonyme Namensräume lösen das Problem der Sichtbarkeit nicht. Sie vermeiden in diesem Kontext nicht einmal Namenskonflikte.



  • l'abra d'or schrieb:

    run.cpp

    #include <iostream>
    using namespace std;
    
    void run()
    {
        int x = 10;
        x++;
        cout << x << endl;
    }
    

    func.h

    void doIt() {
        void run();
        run();
    }
    

    main.cpp

    #include "func.h"
    
    int main() {
        doIt();
    }
    

    Hätte man einen Header "run.h" global in func.h includiert (oder doIt selber global deklariert), könnte man in main.cpp auch direkt auch run() aufrufen. Wenn du das nicht willst machst du eine lokale Funktionsdeklaration und gut ists. Und dein doIt() bleibt immer noch inline!

    Und sowas machst du wirklich?

    Aber eigentlich ein gutes Beispiel warum man lokale Funktionsdeklaration verbieten sollte. Sie erzeugen nur total unübersichtlichen Code, weil so keiner weiß wo run definiert ist. Und run() ist immer noch genauso in main verfügbar.

    int main() {
        void run();
        run();
    }
    


  • Ich habe das auch noch nie gesehen und halte es auch für überflüssig. Ein Sprachfeature, welches von kaum jemandem benutzt wird sollte schon entfent werden, weil es sonst nur Balast ist und (wie hier) mehr Verwirrung, als Nutzen schafft. (Wie viele sind schon über genau diesen Fehler gestossen? - Ich bin mir nicht mehr sicher, wie die Compilermeldung aussieht, aber IIRC nicht sehr hilfreich)



  • drakon schrieb:

    Ich habe das auch noch nie gesehen und halte es auch für überflüssig. Ein Sprachfeature, welches von kaum jemandem benutzt wird sollte schon entfent werden, weil es sonst nur Balast ist und (wie hier) mehr Verwirrung, als Nutzen schafft. (Wie viele sind schon über genau diesen Fehler gestossen? - Ich bin mir nicht mehr sicher, wie die Compilermeldung aussieht, aber IIRC nicht sehr hilfreich)

    Sehe ich auch so. Wenn lokale Funktionsdefinitionen gingen, ja das wäre ein Spaß. Dann sollten auch lokale Funktionsdeklarationen gehen.
    Aber so isses Unfug.
    Nur weiß ich nicht, ob das Entfernen der lokalen Funktionddeklarationen jetzt im C++-Standard 20 Seiten mehr erzeugt oder 20 Seiten wegmacht. Auf jeden Fall bin ich für weniger Regeln oder mehr einfachere.



  • volkard schrieb:

    Nur weiß ich nicht, ob das Entfernen der lokalen Funktionddeklarationen jetzt im C++-Standard 20 Seiten mehr erzeugt oder 20 Seiten wegmacht. Auf jeden Fall bin ich für weniger Regeln oder mehr einfachere.

    Weisst du, was ich glaube? Das das kaum zu gross werden würde. Ein paar Zeilen würde ich mal vermuten, wo einfach gesagt wird, dass das nicht möglich ist. Fertig.



  • drakon schrieb:

    Ich bin mir nicht mehr sicher, wie die Compilermeldung aussieht, aber IIRC nicht sehr hilfreich

    Doch, ziemlich hilfreich. 🙂

    MSVC++ Ausgabe schrieb:

    'MyClass var(void)': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)


  • Administrator

    Naja, ist ja nun im neuen Standard "gelöst":

    int i{1};
    
    void foo()
    {
      MyClass object{};
      std::complex<double> c{1.0, 2.0};
    }
    

    Grüssli



  • Nexus schrieb:

    drakon schrieb:

    Ich bin mir nicht mehr sicher, wie die Compilermeldung aussieht, aber IIRC nicht sehr hilfreich

    Doch, ziemlich hilfreich. 🙂

    MSVC++ Ausgabe schrieb:

    'MyClass var(void)': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)

    Bei welchem Code?
    Ich geb dir mal ein paar Beispiele, wie es aussehn könnte:

    int foo ();
    //...
    std::cout << foo;
    

    error LNK2001: unresolved external symbol "int __cdecl foo(void)" (?foo@@YAHXZ)

    Nicht sehr hilfreich.

    int foo ();
    //...
    foo = 2;
    

    error C2659: '=' : function as left operand

    Nicht sehr hilfreich.

    std::vector<int> foo ();
    //...
    foo.push_back ( 2 );
    

    error C2228: left of '.push' must have class/struct/union

    Nicht sehr hilfreich.

    Man kann sicher noch viel mehr Beispiele mit viel kryptischeren Fehlermeldungen bringen.
    Und das sind Sachen, die immer mal wieder passieren. In der Tat bin ich auf diesen Thread zurückgekommen, weil mir 3. (ja, ich gebs zu) eben gerade passiert ist und ich mich an diese Unterhaltung erinnert habe.



  • Hm, du hast Recht. Ich habe nur ein kurzes Beispiel ausprobiert, bei dem die "Variable" nicht verwendet wurde.

    Ja, natürlich ist es mühsam, dass Konstruktoraufrufe und Funktionsdeklarationen so eine ähnliche Syntax haben. Aber das trifft nicht nur auf Defaultkonstruktoren zu.

    struct MyClass
    {
    	MyClass(double var);
    };
    
    int main()
    {
    	int a;
    	MyClass b(double(a)); // Funktionsdeklaration	
    }
    

    Doch schauen wir uns nochmals die Alternativen an.

    • Solche Ausdrücke immer als Konstruktoraufrufe interpretieren. Scheint auf den ersten Blick praktisch, aber hat den Nachteil, dass der genau gleiche Ausdruck auf globaler Ebene als Funktionsdeklaration interpretiert wird. Dort wiederum sind solche Konstruktoraufrufe nicht möglich. Also hat man eine neue Inkonsistenz, zusätzlich zum Nachteil des folgenden Punkts.
    • Lokale Funktionsdeklarationen verbieten, bei jener Syntax einen Compilerfehler erzeugen. Der Nachteil besteht im fehlenden Feature, welches jedoch – wie bereits gezeigt – in gewissen Situationen nützlich sein kann. Der Vorteil besteht im Compilerfehler. Jedoch ist das momentan schon fast immer der Fall (wenn auch weniger aussagekräftig, was aber hauptsächlich für Anfänger ein Problem darstellt). Die Verwirrung bei Anfängern bleibt hingegen bestehen, weil für diese nicht klar ersichtlich ist, was an dem "Konstruktoraufruf" falsch ist. Schliesslich ist es ebenso eine Inkonsistenz, dass MyClass(arg) und MyClass obj(arg) Konstruktoraufrufe sind, während MyClass() und MyClass obj() unterschiedlich behandelt werden.

    Man behebt also Probleme und schafft sich gleichzeitig neue.

    Und wieso diese ganze Diskussion? Wie oft macht man diesen Fehler? Ich sehe das ähnlich wie bei if (a = 3) . Es gibt Leute, die wählen hier den hässlichen Weg if (3 == a) , um sicherzugehen, obwohl dieser Fehler sehr selten auftritt. Eigentlich ist if (a = 3) sogar schlimmer, weil der Code kompiliert und erst zur Laufzeit merkwürdiges Verhalten erzeugt.

    Ich meine, mit der Begründung, dass ein Feature von wenigen gekannt oder benutzt wird, könnte man gegen einige Sprachmittel aus C++ vorgehen. Die Verwechslungsgefahr mit Konstruktoren gefällt mir natürlich auch nicht, aber die Alternativen halte ich nicht wirklich für besser. Das C++-Standardkommitee scheint den Status Quo ebenfalls für das kleinere Übel zu halten.



  • Lokale Funktionsdeklarationen verbieten, bei jener Syntax einen Compilerfehler erzeugen. Der Nachteil besteht im fehlenden Feature, welches jedoch – wie bereits gezeigt – in gewissen Situationen nützlich sein kann. Der Vorteil besteht im Compilerfehler. Jedoch ist das momentan schon fast immer der Fall (wenn auch weniger aussagekräftig, was aber hauptsächlich für Anfänger ein Problem darstellt). Die Verwirrung bei Anfängern bleibt hingegen bestehen, weil für diese nicht klar ersichtlich ist, was an dem "Konstruktoraufruf" falsch ist. Schliesslich ist es ebenso eine Inkonsistenz, dass MyClass(arg) und MyClass obj(arg) Konstruktoraufrufe sind, während MyClass() und MyClass obj() unterschiedlich behandelt werden.

    Der Vorteil läge darin, dass die Fehlermeldung eindeutig und immer die gleiche wäre. Da würde dann stehen, dass das einfach nicht geht und wahrscheinlich die Klammern zu viel sind. Da muss dann auch ein Anfänger nicht mehr wirklich nachdenken, was er ändern muss und wo der Fehler ist. (Bei meinen obigen Beispielen ist der Fehler schwerer zu erkennen..)

    Und mir ist auch der Sinn dieses "Features" nicht ganz klar. Alles, was man damit machen kann kann man über namespaces viel besser machen.



  • Vielleicht sollte man sich auf einen Kompromiss einigen und in dem Fall einfach eine Warnung ausgeben.


Anmelden zum Antworten