The "C is Efficient" Language Fallacy



  • In java sind ints genau so wenig Referenztypen, das Verhalten ist also genau das selbe, wie wenn du in C++ die ints per Val übergibst.
    Wenn du Referenztypen aus Java nimmst können die dann aber wiederum auch auf das selbe zeigen.


  • Administrator

    JustAnotherNoob schrieb:

    In java sind ints genau so wenig Referenztypen, das Verhalten ist also genau das selbe, wie wenn du in C++ die ints per Val übergibst.
    Wenn du Referenztypen aus Java nimmst können die dann aber wiederum auch auf das selbe zeigen.

    Ich muss zugeben, dass mein Java völlig eingerostet ist, aber wenn ich es korrekt in Erinnerung hatte, dann wird hier nicht per Value übergeben sondern per Referenz. Intern bei der Addition wird das Ergebnis nicht in die referenzierte Variable geschrieben, sondern eine neue erstellt und diese dann der Referenz zugewiesen. Die Referenzen lhs und rhs werden also in der Funktion auf zwei neue Variablen gesetzt und zwar jeweils nach der Addition.

    Das gleiche gilt dann auch bei anderen Objekten in Java wie zum Beispiel java.lang.String . Bei jeder Veränderung wird einem gleich ein neues Objekt zurückgeliefert. Die Veränderungen werden also nicht auf dem Objekt selbst durchgeführt.

    Kann gut sein, dass ich hier völlig auf dem Holzweg bin, wie gesagt, mein Java ist eingerostet. Würde mich aber freuen, wenn mich da jemand korrigieren könnte, falls ich falsch liege.

    Grüssli



  • aber wenn ich es korrekt in Erinnerung hatte, dann wird hier nicht per Value übergeben sondern per Referenz.

    http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html
    -> nein, das wird nicht als Referenz übergeben.

    String ist nochmal ein Sonderfall, weil es ein Objekt ist, dass von Literalen erzeugt wird, aber normale Objekte können durchaus aufeinander verweisen, mit

    Object a = new Object();
    Object b = a;
    

    verweist b afaik auf a.



  • Dravere schrieb:

    JustAnotherNoob schrieb:

    In java sind ints genau so wenig Referenztypen, das Verhalten ist also genau das selbe, wie wenn du in C++ die ints per Val übergibst.
    Wenn du Referenztypen aus Java nimmst können die dann aber wiederum auch auf das selbe zeigen.

    Ich muss zugeben, dass mein Java völlig eingerostet ist, aber wenn ich es korrekt in Erinnerung hatte, dann wird hier nicht per Value übergeben sondern per Referenz. Intern bei der Addition wird das Ergebnis nicht in die referenzierte Variable geschrieben, sondern eine neue erstellt und diese dann der Referenz zugewiesen. Die Referenzen lhs und rhs werden also in der Funktion auf zwei neue Variablen gesetzt und zwar jeweils nach der Addition.

    Das gleiche gilt dann auch bei anderen Objekten in Java wie zum Beispiel java.lang.String . Bei jeder Veränderung wird einem gleich ein neues Objekt zurückgeliefert. Die Veränderungen werden also nicht auf dem Objekt selbst durchgeführt.

    Kann gut sein, dass ich hier völlig auf dem Holzweg bin, wie gesagt, mein Java ist eingerostet. Würde mich aber freuen, wenn mich da jemand korrigieren könnte, falls ich falsch liege.

    Grüssli

    Java ist wie C und C++ auch "call by Value", sprich die Parameter werden immer kopiert. In Java werden die primitiven Typen aber auch wie in C und C++ gehandhabt und nicht wie die Java-Objekte (beidenen ist nur Zugriff über Zeiger möglich).


  • Administrator

    JustAnotherNoob schrieb:

    http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html
    -> nein, das wird nicht als Referenz übergeben.

    In dem Link steht dazu allerdings nichts 😉
    In meinen Vorlesungsnotizen allerdings schon und zwar genau so, wie ich es gesagt hatte. Würde mich aber nicht erstaunen, wenn dies falsch ist. Wäre ja typisch, geht genau gleich zu wie in C++

    Naja, dachte ich hätte es womöglich begriffen, aber das ist wohl definitiv nicht der Fall. Muss ich mich da nochmals ein wenig reinarbeiten. Danke jedenfalls.

    Grüssli



  • In dem Link steht dazu allerdings nichts

    ups, ist aber trotzdem richtig - probiers aus.



  • Java ist ausschließlich call-by-value. Bei Objekt-Typen werden Referenzen eben by-value übergeben. Call-by-reference ist was völlig anderes.



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



  • Shade Of Mine schrieb:

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

    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).



  • 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).

    void recreate(String s) {
      s=new String("recreated");
    }
    

    Das ist Call By Value. Und das ist kein verstecktes detail. Deshalb gibt es ja auch zB das idiom des object wrappers um call by reference zu ermoeglichen:

    class StringWrapper {
    public StringWrapper(String value) {
      this.value = value;
    }
      public String value;
    };
    
    void recreate(StringWrapper s) {
      s.value=new String("recreated");
    }
    


  • +fricky schrieb:

    einen grossteil der optimierung macht die java-VM zur laufzeit, nicht der compiler. damit hat Java natürlich sehr viel mehr optimiermöglichkeiten, als programmiersprachen, deren compiler starren maschinencode für bestimmte CPUs erzeugen müssen. http://en.wikipedia.org/wiki/Java_performance#Adaptive_optimization
    🙂

    Das hat doch mit dem Thema nichts zu tun. Es sei denn, du meinst, dass der Jitter zur Laufzeit das Aliasing analysiert und das will ich doch mal schwer bezweifeln.

    Dravere schrieb:

    Bei Java sieht dies allerdings etwas anders aus:

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

    val wird hier unverändert bleiben, egal wie man die Funktion aufruft.

    Das Bespiel verhält sich in C++ exakt wie in Java, da wie schon gesagt int (und selbst Integer - Ausnahmen ahoi!) nicht als Referenzen behandelt werden.

    So, und jetzt mal Aliasing in Java:

    class test{
    
      class X{
        public X(int x){
          this.x = x;
        }
        public int x;
      }
    
      public void foo(X lhs, X rhs, X val){
        lhs.x += val.x;
        rhs.x += val.x;
      }
    
      public test(){
        X lhs = new X(1);
        X rhs = new X(2);
        X val = new X(3);    
    
        foo(lhs, lhs, val);
    
        System.out.println(lhs.x); // 7
      }
    
      public static void main(String args[]){
        test t = new test();
      }
    }
    

    Der Compiler kann nicht wissen, ob hinter den Referenzen die gleichen Objekte stecken.



  • maximAL schrieb:

    Es sei denn, du meinst, dass der Jitter zur Laufzeit das Aliasing analysiert und das will ich doch mal schwer bezweifeln.

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

    maximAL schrieb:

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

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



  • +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).
    🙂


Anmelden zum Antworten