The "C is Efficient" Language Fallacy



  • +fricky schrieb:

    so ähnlich. warum hältst du das für so unwahrscheinlich?

    Weil sich die Referenzen im Programmablauf ständig ändern können und man das Aliasing ständig prüfen müsste, was beim Interpretieren mehr kostet als es bringt und einen Jitter ad absurdum führt (denn kompilieren ist teuer).

    +fricky schrieb:

    foo(lhs, rhs, val);
    System.out.println(lhs.x); // 4

    Ja. Ich wollte damit was zum Ausdruck bringen.



  • maximAL schrieb:

    +fricky schrieb:

    so ähnlich. warum hältst du das für so unwahrscheinlich?

    Weil sich die Referenzen im Programmablauf ständig ändern können und man das Aliasing ständig prüfen müsste, was beim Interpretieren mehr kostet als es bringt und einen Jitter ad absurdum führt (denn kompilieren ist teuer).

    versteh ich nicht. wenn jemand sowas programmiert, dass man über zwei verschiedene referenzen ein objekt verändern kann, dann ist das entweder absicht, oder er hat 'nen fehler gemacht. da muss nix ständig geprüft werden.

    maximAL schrieb:

    +fricky schrieb:

    foo(lhs, rhs, val);
    System.out.println(lhs.x); // 4

    Ja. Ich wollte damit was zum Ausdruck bringen.

    dass man sich vertippen kann?
    🙂



  • Shade Of Mine schrieb:

    asc schrieb:

    Das mag sein, aber für den Anwender erscheint es bei Objekten anders (Wie es konkret umgesetzt wird, interessiert Viele nicht, sofern sie das Ergebnis verstehen).

    ...Das ist Call By Value. Und das ist kein verstecktes detail.

    Wie du vielleicht gelesen hatte, habe ich explizit von Objekten gesprochen. Nehmen wir folgendes Beispiel aus einem Buch:

    import java.awt.*; 
    
    public class InitPoint 
    { 
      static void clear( Point p ) 
      { 
        p.setLocation( 0, 0 ); 
      } 
    
      public static void main( String[] args ) 
      { 
        Point q = new Point( 47, 11 );   // Coordinates (x=47,y=11) 
        clear( q ); 
        System.out.println( q.x );   // 0 
      } 
    }
    

    Rein Optisch sieht es bei der Methode clear für mich wie eine Wertübergabe unter C++ aus. Dennoch kann man Änderungen wie bei einer C++ Referenz machen. Tatsächlich ist es aber eher ein Zeiger der kopiert wird, so das ein new an der Stelle tatsächlich keine Außenwirkung hat.

    Ich persönlich finde das Verhalten (sowohl unter Java als auch C#) verwirrend. Ich weiß nicht mehr ob man in Java eigene Werttypen (was in C# definitiv geht) definieren kann, sehe es aber als Problematisch an, wenn man für einen Parameter erst bei der Betrachtung des Typen weiß, ob eine Änderung an diesem das Original ändert oder nicht.

    Und daher sehe ich hier tatsächlich ein verstecktes Detail.



  • dass man sich vertippen kann?

    Dass hier nicht optimiert werden kann.



  • JustAnotherNoob schrieb:

    dass man sich vertippen kann?

    Dass hier nicht optimiert werden kann.

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind (bei dem tippfehler-beispiel) und einen davon von vorn herein weglassen. optimierungen zur laufzeit sind dazu noch nicht mal nötig.
    🙂



  • das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind (bei dem tippfehler-beispiel) und einen davon von vorn herein weglassen. optimierungen zur laufzeit sind dazu noch nicht mal nötig.

    Ich ergänze: dass hier nichts optimiert werden kann, was es nicht in C++ auch kann.



  • Shade Of Mine schrieb:

    Java hat sogar nur Call By Value - ein Call By Reference gibt es garnicht 🙄

    Genau das sagte ich doch...

    asc schrieb:

    Rein Optisch sieht es bei der Methode clear für mich wie eine Wertübergabe unter C++ aus. Dennoch kann man Änderungen wie bei einer C++ Referenz machen. Tatsächlich ist es aber eher ein Zeiger der kopiert wird, so das ein new an der Stelle tatsächlich keine Außenwirkung hat.

    Richtig. Trotzdem ein lupenreines call-by-value Beispiel.

    Ich persönlich finde das Verhalten (sowohl unter Java als auch C#) verwirrend. Ich weiß nicht mehr ob man in Java eigene Werttypen (was in C# definitiv geht) definieren kann, sehe es aber als Problematisch an, wenn man für einen Parameter erst bei der Betrachtung des Typen weiß, ob eine Änderung an diesem das Original ändert oder nicht.

    In Java ist das sauber gelöst. Von Primitiven abgesehen (die eh immutable sind) , gibt es keine Wertobjekte.
    In C# ist das anders: http://www.geocities.com/csharpfaq/structs.html



  • asc schrieb:

    Rein Optisch sieht es bei der Methode clear für mich wie eine Wertübergabe unter C++ aus. Dennoch kann man Änderungen wie bei einer C++ Referenz machen.

    du hast zuviel in C programmiert. vielleicht hilfts dir, wenn du dir vorstellst, dass java-referenzen sowas wie pointer sind.

    JustAnotherNoob schrieb:

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind (bei dem tippfehler-beispiel) und einen davon von vorn herein weglassen. optimierungen zur laufzeit sind dazu noch nicht mal nötig.

    Ich ergänze: dass hier nichts optimiert werden kann, was es nicht in C++ auch kann.

    rischtich, allerdings kann die Java-VN noch zur laufzeit optimieren (und tut dies oft auch).
    🙂



  • +fricky schrieb:

    asc schrieb:

    Rein Optisch sieht es bei der Methode clear für mich wie eine Wertübergabe unter C++ aus. Dennoch kann man Änderungen wie bei einer C++ Referenz machen.

    du hast zuviel in C programmiert. vielleicht hilfts dir, wenn du dir vorstellst, dass java-referenzen sowas wie pointer sind.

    JustAnotherNoob schrieb:

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind (bei dem tippfehler-beispiel) und einen davon von vorn herein weglassen. optimierungen zur laufzeit sind dazu noch nicht mal nötig.

    Ich ergänze: dass hier nichts optimiert werden kann, was es nicht in C++ auch kann.

    rischtich, allerdings kann die Java-VN noch zur laufzeit optimieren (und tut dies oft auch).
    🙂

    Das kann ich mit dem VC9 doch so ähnlich auch, da kompilier ich die Anwendung dann führ ich sie aus und anschließend kompilier ich sie erneut, nur dieses mal hat der Kompiler zusätzliche Informationen über das Laufzeitverhalten 🙂

    Die Kritik an den Java Referenzen ist doch unberechtigt, denn weder in C noch in Java kann ich sagen was foo( eineVariable ); tut, abgesehen davon, dass eineVariable nicht geändert wird. Aber wenn eineVariable in C ein Zeiger und in Java ein Objekt (bzw. eine Objektreferenz) ist, dann weiß ich erst nachdem ich nachgeschaut habe was eineVariable ist ob das refenzierte Objekt (möglicherweise) geändert wird.



  • C++-Programmierender schrieb:

    Das kann ich mit dem VC9 doch so ähnlich auch, da kompilier ich die Anwendung dann führ ich sie aus und anschließend kompilier ich sie erneut, nur dieses mal hat der Kompiler zusätzliche Informationen über das Laufzeitverhalten

    klar, das musste nur irgendwie automatisieren, also quelltext, compiler, linker und analysesystem irgendwie zusammenbringen, so dass der code in abhängigkeit von der umgebung immer wieder neu compiliert wird. 'closed world assumptions' würde prof84 jetzt buzzworden.
    🙂



  • asc schrieb:

    Wie du vielleicht gelesen hatte, habe ich explizit von Objekten gesprochen.

    Dann ist fuer dich also ein

    void strcpy(char* trg, char* src) {
      while(*trg++=*src++);
    }
    

    ebenfalls ein call by reference?

    Ne ne ne.
    Du kannst nicht einfach die Sachen definieren wie du willst. Java kennt nur call by value. Weil Objekte eben referenzen sind. Das ist relevant zu wissen. Natuerlich kannst du die objekte die referenziert werden aendern, aber eben nicht die referenzen selber.

    denk einfach mal an:

    public class InitPoint 
    { 
      static void clear( Point p ) 
      { 
        p=new Point( 0, 0 ); 
      } 
    
      public static void main( String[] args ) 
      { 
        Point q = new Point( 47, 11 );   // Coordinates (x=47,y=11) 
        clear( q ); 
        System.out.println( q.x );   // nicht 0 
      } 
    }
    

    Call by reference wuerde hier q auf (0,0) setzen. Aber es ist call by value, ergo passiert garnix. Das ist sehr relevant zu wissen, da du zB keine delete() funktion schreiben kannst die eine referenz auf null setzt.

    es ist also kein verstecktes detail sondern eine klare und einfache design entscheidung gewesen. alles wird by value uebergeben.



  • +fricky schrieb:

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind

    Das kann meistens eben nicht zur Kompilierzeit festgestellt werden.

    +fricky schrieb:

    (bei dem tippfehler-beispiel)

    ...ich geb dir gleich Tippfehler...



  • maximAL schrieb:

    +fricky schrieb:

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind

    Das kann meistens eben nicht zur Kompilierzeit festgestellt werden.

    +fricky schrieb:

    (bei dem tippfehler-beispiel)

    ...ich geb dir gleich Tippfehler...

    Du weißt doch es genügt, wenn der Kompiler Code erzeugt der in 99% der Fälle korrekt ist.



  • maximAL schrieb:

    +fricky schrieb:

    das sagst du so. allein schon der compiler könnte z.b. die methode inlinen, dabei feststellen, dass lhs und rhs gleich sind

    Das kann meistens eben nicht zur Kompilierzeit festgestellt werden.

    das ist sehr einfach festzustellen. du übergibst nämlich zwei mal das gleiche objekt. selbst meine Java-IDE (intellij-idea) hat bei deinem beispiel gemeckert, dass hier was nicht stimmen kann.
    🙂



  • void foo(int* lhs, int* rhs, int* val)
    {
      *lhs += *val;
      *rhs += *val;
    }
    

    OMG, mein Compiler kann diese Zeilen nicht optimieren. Parallelisierung ist nie einfach und die eigentliche Performance holt man nicht aus der Microoptimierung.

    adaptive optimization may take advantage

    Irgendwie stoert mich der Konjunktiv. Was ist denn nun wirklich?



  • knivil schrieb:

    void foo(int* lhs, int* rhs, int* val)
    {
      *lhs += *val;
      *rhs += *val;
    }
    

    OMG, mein Compiler kann diese Zeilen nicht optimieren.

    schreib mal 'restrict' vor die pointer (dein compiler muss aber C99 kennen, z.b. GCC). vielleicht tut er's ja dann.
    🙂



  • knivil schrieb:

    void foo(int* lhs, int* rhs, int* val)
    {
      *lhs += *val;
      *rhs += *val;
    }
    

    OMG, mein Compiler kann diese Zeilen nicht optimieren. Parallelisierung ist nie einfach und die eigentliche Performance holt man nicht aus der Microoptimierung.

    Das Problem ist, dass der Compiler quasi nichts parallelisieren kann. Das ist ein relevantes Problem.



  • schreib mal 'restrict' vor die pointer (dein compiler muss aber C99 kennen, z.b. GCC). vielleicht tut er's ja dann.

    bist du Reporter? 🤡



  • Das Problem ist, dass der Compiler quasi nichts parallelisieren kann. Das ist ein relevantes Problem.

    Nur zur Klarstellung: Was, wie und in welchem Massstab bedeutet hier parallelisieren? UV-Pipeline, Mehrkern, ... ?

    C ist halt nah an der Maschine. Entweder abstrahiert man von der Maschine oder spezialisiert man fuer eine Maschine. C oder auch C++ tut beides nicht. Das ist kein Nachteil. Warum soll C++ alles koennen? Wenn man so etwas haben moechte, dann parallelisiert man selbst oder man nimmt sich z.B. eine funktionale Sprache und laesst sich parallelen Code generieren. In beiden Faellen muss man Gehirnschmalz investieren, zum einen parallelisiert man selbst oder muss halt die neue Sprache lernen. Und wenn jemand behaupt, dass z.B. Java schneller sein soll als C++, dann hat er vielleicht hier und da etwas weniger Gehirnschmalz investiert. Und dann auf die super tolle Jit-Blub verweisen, ich weiss nicht ...

    Ich koennte ja noch 'ne Geschichte zum Besten geben mit Agent Nero in Mission Iso-Image brennen. Installer: 500 MByte ... die modernen Alleskoenner. Ich will sie nicht.



  • knivil schrieb:

    Nur zur Klarstellung: Was, wie und in welchem Massstab bedeutet hier parallelisieren? UV-Pipeline, Mehrkern, ... ?

    Jede Art von Parallelisierung.

    Das Problem ist nämlich, dass jedes Statement dass Pointer liest oder schreibt jedes andere Statement verändern kann. Egal welche Art der Parallelisierung - sogar in der Pipeline selber drinnen, ist mit Zeigern enorm problematisch.

    C ist halt nah an der Maschine. Entweder abstrahiert man von der Maschine oder spezialisiert man fuer eine Maschine. C oder auch C++ tut beides nicht. Das ist kein Nachteil. Warum soll C++ alles koennen? Wenn man so etwas haben moechte, dann parallelisiert man selbst oder man nimmt sich z.B. eine funktionale Sprache und laesst sich parallelen Code generieren.

    Es ist ein relevantes Problem dass C/C++ Code einfach in gewissen Situationen lahm ist. Da kannst du auch kein Gehirnschmalz oder sonstwas investieren - dieser Aspekt an C++ suckt einfach. Deshalb ist dringend restrict in C++ notwendig...

    Und wenn jemand behaupt, dass z.B. Java schneller sein soll als C++, dann hat er vielleicht hier und da etwas weniger Gehirnschmalz investiert. Und dann auf die super tolle Jit-Blub verweisen, ich weiss nicht ...

    Es ist aber so. In gewissen Situationen wird Java immer schneller sein als C++.


Anmelden zum Antworten