Klasse: "Pass by Reference" falsch?


  • Administrator

    Bashar schrieb:

    Dravere schrieb:

    Nein, das verwirrt schlussendlich nur jeden Anfänger.

    Da müssen sie durch. Auf dem Weg vom Anfänger zum Fortgeschrittenen liegt irgendwann die Einsicht, dass es so ist.

    Gut, man kann sogar das Anfänger wegnehmen. Das verwirrt jeden. Es macht überhaupt keinen Sinn, dies als Call-By-Value zu bezeichnen. Es ist schlussendlich genau das Gleiche wie in C++ mit dem Referenz-Operator einfach nur implizit.

    Wenn du in einem Gespräch über Code dies als Call-By-Value bezeichnest, wird dich jeder nur seltsam anschauen und dich nicht verstehen, da es völlig irrelevant ist, wie das der Kompiler oder Runtime dann tatsächlich umsetzt. Das gilt für C++ wie auch für C# und daher ist das auf dem Sprach-Level ein Call-By-Reference. Ob dass dann in der Ausführung als Call-By-Value umgesetzt wird, ist völlig schnuppe.

    Bashar schrieb:

    Es ist z.B. unmöglich, Polymorphie einzusetzen, wenn man nicht kapiert, dass eine Objektvariable eine Referenz ist.

    Ist auf dem Sprach-Level völlig irrelevant, wie das umgesetzt wird.

    Meiner Meinung nach muss man hier einfach zwei Dinge klar auseinander halten. Es gibt das Sprach-Level und das Runtime-Level. Und es dürfen für diese beiden Levels unterschiedliche Bezeichnungen verwendet werden. Die Umsetzung im Runtime-Level ist allerdings völlig irrelevant für das Sprach-Level.

    Bashar schrieb:

    Ist der Rest meines Postings nach dem ersten Satz zu schwierig zu verstehen?

    Nein, habe es aus irgendeinem Grund nur nicht gesehen.

    Grüssli



  • Dravere schrieb:

    Bashar schrieb:

    Dravere schrieb:

    Nein, das verwirrt schlussendlich nur jeden Anfänger.

    Da müssen sie durch. Auf dem Weg vom Anfänger zum Fortgeschrittenen liegt irgendwann die Einsicht, dass es so ist.

    Gut, man kann sogar das Anfänger wegnehmen. Das verwirrt jeden. Es macht überhaupt keinen Sinn, dies als Call-By-Value zu bezeichnen. Es ist schlussendlich genau das Gleiche wie in C++ mit dem Referenz-Operator einfach nur implizit.

    siehe unten

    Wenn du in einem Gespräch über Code dies als Call-By-Value bezeichnest, wird dich jeder nur seltsam anschauen

    Unplausibel, unrealistisch, unbeweisbar. Was soll das?

    und dich nicht verstehen, da es völlig irrelevant ist, wie das der Kompiler oder Runtime dann tatsächlich umsetzt.

    Ist es in der Tat, denn es geht nicht um die Umsetzung.

    Das gilt für C++ wie auch für C# und daher ist das auf dem Sprach-Level ein Call-By-Reference.

    Achso, das ist so, weil es so ist. Verstanden.

    Den Rest lösch ich mal weg. Über die Umsetzung oder irgendwelche Runtime-Ebenen hab ich nie was gesagt.

    Bashar schrieb:

    Ist der Rest meines Postings nach dem ersten Satz zu schwierig zu verstehen?

    Nein, habe es aus irgendeinem Grund nur nicht gesehen.

    Und jetzt immer noch ignoriert. In Kurzform: Ich akzeptiere keine Analogieschlüsse, die von C++ ausgehen.


  • Administrator

    Du weisst es, alle Argumente welche etwas anderes sagen sind nach deiner Vorstellung nicht aktzeptabel und damit erübrigt sich jede Diskussion. Habe ich auch nichts dagegen. Soll sich jeder selber eine Meinung dazu bilden. Ich werde es definitiv nie als Call-By-Value bezeichnen.

    Grüssli



  • Dravere schrieb:

    Du weisst es, alle Argumente welche etwas anderes sagen sind nach deiner Vorstellung nicht aktzeptabel und damit erübrigt sich jede Diskussion.

    Wie kommst du darauf? Ganz schlechter Stil. 👎



  • DarkShadow44 schrieb:

    [...] dass in C# alle Objekte von Klassen (nur Klassen, nicht Structs) eigentlich Pointer sind. und die verhalten sich genau so wie C++ Pointer.

    Nein, es ist ein verbreiteter Mythos das eine Referenz von C# das Gleiche sei wie ein Pointer in C++, aber es ist dennoch falsch.

    Der C++-Pointer zeigt auf eine Adresse im Speicher.

    Die C#-Referenz referenziert ein Objekt dessen Adresse erst durch die Speicherverwaltung aufgelöst wird. Die Referenz selber ist aber keine Speicheradresse und enthält auch keine Speicheradresse.

    Dravere schrieb:

    Es ist schlussendlich genau das Gleiche wie in C++ mit dem Referenz-Operator einfach nur implizit.

    eben genau das ist es nicht. Die Referenz aus C++ und die Referenz von C# sind nicht das Gleiche. Siehe oben.



  • Nein, es ist ein verbreiteter Mythos das eine Referenz von C# das Gleiche sei wie ein Pointer in C++, aber es ist dennoch falsch.

    Stimmt schon, hinter den Kulissen sieht es bei C# ganz anders aus. Aber das handelt die CLR vollkommen transparent, letztlich verhalten sich "C#-Referenzen" genau so als ob sie Pointer wären. OK, nicht überall, aber zumindest was die Parameterübergabe angeht. Ob eine Methode das Objekt direkt über die Addresse oder über ein Handle und den Umweg über die CLR referenziert ändert für den normalen Programmierer nichts. In beiden Fällen hat man irgendwas was nur auf das Objekt zeigt, sei es nun Handle oder die native Adresse.
    Die Runtime übernimmt die Auflösung der Adressen, deshalb sind "C++ Pointer" und "C# Referenzen" vom Verhalten für den Entwickler durchaus gleich.


  • Administrator

    Ich kann mich nur wiederholen. Unterscheidet zwischen Sprach- und Runtime-Level. Auf dem Sprach-Level ist es ein Call-By-Reference und auf dem Runtime-Level ein Call-By-Value. Was bitte schön spricht dagegen?

    Ein Call-By-Value heisst, dass das Objekt kopiert wird. Das ist doch einfach nur verwirrend in C#!

    class MyObject
    {
    };
    
    // ...
    
    void Foo(MyObject obj) { }
    
    // ...
    MyObject obj = new MyObject();
    Foo(obj);
    

    Hier wird doch niemand vernünftigerweise davon reden, dass an Foo eine Kopie von obj übergeben wird? Es ist zwar technisch korrekt, aber damit wird etwas nach vorne geholt, welches von der Sprache transparent gekapselt wird, dass überhaupt keinen Vorteil im Verständnis bringt. Wieso also diese unsinnige Bezeichnung verwenden, welche überhaupt keinen Vorteil bringt?

    Es ist für jeden deutlich verständlicher, wenn man davon spricht, dass eine Referenz auf das Objekt hier übergeben wird und wir somit ein Call-By-Reference haben. Völlig egal und losgeläst, was die Runtime nun macht.

    Theoretisch dürfte diese ja auch das Objekt kopieren, auf der Kopie arbeiten und den Speicher wieder 1:1 auf das ursprüngliche Objekt zurückmappen, wenn es denn in der CLR nicht anders standardisiert wäre.

    Ich plädiere nur dafür, dass man diese beiden Level voneinander klar trennen sollte.

    Grüssli



  • Sorry, ich bin normalerweise immer dabei, wenn man mal fünfe gerade sein lassen soll, aber ich halte es für wichtig, dass man hier sieht, versteht und sagt, dass es im Endeffekt call by value ist.
    Wenn in C# void foo (Object o) von euch als call by reference bezeichnet wird, ist dann void foo(ref Object x) etwa "mehr" call by reference? 😉 Wenn ich Anfänger wäre, würde ich mich fragen: Hääää?

    Man kann es für Wortklauberei halten, ist es aber nicht. Es ist auch nicht schwer zu verstehen, insofern sollte es nicht schwer sein, es korrekt zu benennen. Es stiefelt ja auch keiner durch die Gegend und sagt int x; wäre die Definition und nicht die Deklaration von x.



  • Dravere schrieb:

    Ich kann mich nur wiederholen. Unterscheidet zwischen Sprach- und Runtime-Level. Auf dem Sprach-Level ist es ein Call-By-Reference und auf dem Runtime-Level ein Call-By-Value. Was bitte schön spricht dagegen?

    Also ich rede über die Semantik, was du wohl Sprachebene nennst, nicht über die Umsetzung.

    Ein Call-By-Value heisst, dass das Objekt kopiert wird.

    Nein, es heißt, dass das Argument kopiert wird. Das Argument ist in dem Fall eine Referenz.

    Hier wird doch niemand vernünftigerweise davon reden, dass an Foo eine Kopie von obj übergeben wird?

    Ja, weil das überflüssig ist (und daher ungewohnt klingt). Bei Bar(42) sagt man ja auch nicht, dass eine Kopie von 42 übergeben wird, auch wenn es eigentlich stimmt.

    Es ist völlig richtig, dass eine Referenz auf ein Objekt übergeben wird, nur führt es in die Irre, das Call-by-reference zu nennen. Wie ich schon sagte, man muss irgendwann intellektuell den Schritt machen zu akzeptieren, dass Variablen von Klassentypen (und Arrays) Referenzen sind. Das ist kein Aspekt der technische Umsetzung, das ist IMO essentiell zum Verständnis.

    Nochmal ein Beispiel:

    Derived obj = new Derived();
    Base b = obj;
    

    Wie willst du sowas verstehen, wenn für dich obj das Objekt ist? Was ist dann b? Eigentlich auch obj ... aber hat obj jetzt einen anderen Typ? Nope, das Objekt "schwebt" im Hintergrund, und die beiden Variablen sind unterschiedliche Sichten darauf. Oder halt Referenzen.

    Es ist für jeden deutlich verständlicher, wenn man davon spricht, dass eine Referenz auf das Objekt hier übergeben wird

    Korrekt.

    und wir somit ein Call-By-Reference haben.

    Das folgt daraus nicht. Und es ist IMO irreführend. Schon allein, weil du dann nicht weißt, wie du die Übergabe mithilfe von ref nennen sollst. Aber auch ohne das, die gleiche Diskussion gibts schließlich auch in Java.



  • GPC schrieb:

    Es stiefelt ja auch keiner durch die Gegend und sagt int x; wäre die Definition und nicht die Deklaration von x.

    Hä?



  • volkard schrieb:

    GPC schrieb:

    Es stiefelt ja auch keiner durch die Gegend und sagt int x; wäre die Definition und nicht die Deklaration von x.

    Hä?

    Zumal das hier im Forum jemand macht.



  • GPC schrieb:

    Es stiefelt ja auch keiner durch die Gegend und sagt int x; wäre die Definition und nicht die Deklaration von x.

    "int x;" ist sowohl Deklaration als auch eine Definition. Deklarieren darfst du sooft zu willst, wenn du zweimal "int x;" im selben Block schreibst beschwert sich der Compiler. In C# ist Deklaration aber praktisch immer auch gleich Definition und andersrum.
    Aber das gehört nicht hierher.

    Bashar schrieb:

    Nochmal ein Beispiel:

    Derived obj = new Derived();
    Base b = obj;
    

    Wie willst du sowas verstehen, wenn für dich obj das Objekt ist? Was ist dann b? Eigentlich auch obj ... aber hat obj jetzt einen anderen Typ? Nope, das Objekt "schwebt" im Hintergrund, und die beiden Variablen sind unterschiedliche Sichten darauf. Oder halt Referenzen.

    Es ist für jeden deutlich verständlicher, wenn man davon spricht, dass eine Referenz auf das Objekt hier übergeben wird

    Korrekt.

    und wir somit ein Call-By-Reference haben.

    Das folgt daraus nicht. Und es ist IMO irreführend. Schon allein, weil du dann nicht weißt, wie du die Übergabe mithilfe von ref nennen sollst. Aber auch ohne das, die gleiche Diskussion gibts schließlich auch in Java.

    Und ich finde es verwirrend es nicht "by reference" zu nennen wenn doch eine Referenz übergeben wird. Das dann als "by value" zu bezeichnen passt nicht.

    Die Übergabe mittels ref ist dann die Übergabe der Referenz by Referenze, was denn sonst ?



  • DarkShadow44 schrieb:

    Die Übergabe mittels ref ist dann die Übergabe der Referenz by Referenze, was denn sonst ?

    Du widersprichst dir damit selbst, denn nach der Logik müsste die Übergabe ohne ref "Übergabe der Referenz by Value" heißen.



  • DarkShadow44 schrieb:

    Deklarieren darfst du sooft zu willst, wenn du zweimal "int x;" im selben Block schreibst beschwert sich der Compiler.

    Du meinst sicher, dass ich so oft definieren darf, wie ich will. Vielleicht liest du noch mal genau nach, was der Unterschied zwischen Deklaration und Definition ist 😉

    DarkShadow44 schrieb:

    Und ich finde es verwirrend es nicht "by reference" zu nennen wenn doch eine Referenz übergeben wird. Das dann als "by value" zu bezeichnen passt nicht.

    Die Übergabe mittels ref ist dann die Übergabe der Referenz by Referenze, was denn sonst ?

    Ich finde, diese beiden Aussagen schließen sich gegenseitig aus.



  • GPC schrieb:

    Du meinst sicher, dass ich so oft definieren darf, wie ich will. Vielleicht liest du noch mal genau nach, was der Unterschied zwischen Deklaration und Definition ist 😉

    <a href= schrieb:

    http://www.c-plusplus.net/forum/61231-full pumuckl">

    class foo;          // <-- Deklaration von foo 
      
    class foo {         // <-- Definition  von foo 
     /*...*/
    }; 
        
    extern int yay;     // <-- Deklaration von yay 
    int yay;            // <-- Definition  von yay
    

    Wo liegt jetzt mein Fehler ? 😕

    Bashar schrieb:

    DarkShadow44 schrieb:

    Die Übergabe mittels ref ist dann die Übergabe der Referenz by Referenze, was denn sonst ?

    Du widersprichst dir damit selbst, denn nach der Logik müsste die Übergabe ohne ref "Übergabe der Referenz by Value" heißen.

    Naja letztlich wird bei einer Übergabe immer etwas kopiert, und sei es nur die Referenz. Ja, insofern müsste es ohne ref "Übergabe der Referenz by Value" und mit ref "Übergabe der Referenz by Referenze by Value" heißen. Da würde ich jeweils das letzte "by value" allerdings weglassen, da klar ist dass die Referenz kopiert werden muss, die Methode muss schließlich irgendwas erhalten.



  • Ich hab irgendwie das Gefühl, du hast gar keine Meinung zu dem Thema und reimst dir von Post zu Post irgendwas zusammen. Auch gut, du wirst wohl irgendwann bei der etablierten Bezeichnung ankommen 😉



  • Bashar schrieb:

    Ich hab irgendwie das Gefühl, du hast gar keine Meinung zu dem Thema und reimst dir von Post zu Post irgendwas zusammen. Auch gut, du wirst wohl irgendwann bei der etablierten Bezeichnung ankommen 😉

    Und ich glaube du versuchst es nicht zu verstehen.
    Nochmal als einfachere Fassung:
    By value heißt dass das objekt kopiert wird. By Reference heißt dass es nicht kopiert wird. Ergo:

    void method(Class1 obj) // by reference (auch wenn die referenz auf runtime level sicher by value übergeben wird)
    


  • DarkShadow44 schrieb:

    Und ich glaube du versuchst es nicht zu verstehen.
    Nochmal als einfachere Fassung:

    Einfacher heißt in dem Fall, dass du den größeren Blödsinn ("reference by value") weglässt? Dazu hätte ich ja auch noch was zu sagen gehabt 😉

    By value heißt dass das objekt kopiert wird.

    Nein, das Argument wird kopiert.

    By Reference heißt dass es nicht kopiert wird.

    Nein. Es heißt, dass das Argument als (implizite) Referenz übergeben wird.

    Ergo:

    void method(Class1 obj) // by reference (auch wenn die referenz auf runtime level sicher by value übergeben wird)
    

    Es geht nicht um die Runtime, sondern um die Semantik.



  • Dravere schrieb:

    Ich kann mich nur wiederholen. Unterscheidet zwischen Sprach- und Runtime-Level.
    (...)

    Ich glaub es geht wirklich darum was Dravere schreibt.

    Also uns wurde früher in C++ eben so beigebracht, dass:

    int *i = new int();
    foo(*i) //by value
    foo(i) //by referenz
    

    Dabei ist mir sehr wohl bewusst, dass der Parameter by value übergeben wird.
    Folgendes funktioniert also natürlich nicht:

    void foo(int *i) 
    {i = nullptr;}
    


  • Dazu hab ich doch auch schon was gesagt. Die Übergabe eines Pointers kann Call-by-reference simulieren, aber es ist weiterhin Call-by-value.

    Bei C++-Referenzen kann man sich streiten -- IMHO gehört zum Konzept von Call-by-reference, dass sich das nur auf Parameter bezieht, C++ hat Referenzen jedoch als normalen Datentyp. Nun sind C++-Referenzen keine Objekttypen, können also nicht kopiert werden. Kann man also davon sprechen, dass da eine Referenz by-value übergeben wird, eher nicht. Wird das Argument also by-reference übergeben? Eigentlich schon, aber diese Art der Argumentübergabe unterscheidet sich genaugenommen in nichts von jeder anderen Argumentübergabe, da dort i.A. nicht kopiert wird, sondern Formalparameter mit Aktualarametern in dergleichen Weise wie sonst auch initialisiert werden. Daher tendiere ich zu der Meinung, dass das Konzept von Call-by-reference im Grunde genommen überholt ist und insbesondere in C++ sinnlos geworden ist. Bei Sprachen wie C# passt es jedoch noch. Das ist ja dasselbe wie z.B. in Pascal mit seinen var-Parametern.
    </imho>


Anmelden zum Antworten