Pass by value erzwingen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

sma hat geschrieben:BlackVivi, dein Beispiel zeigt etwas GANZ ANDERES.
Gaaaanz ruhig... Das war nur'n Scherz von meiner Seite, um dich'n bissel anzustacheln. Mehr nicht. Hab ja danach geschrieben, dass ich auf deiner Seite steh oO' Und die Smilies dazu... Ich weiß, dass es was anderes ist'ne Methode von einem Objekt aufzurufen als'ne Zuweisung an einer Referenz zu machen.

(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

BlackVivi hat geschrieben:Gaaaanz ruhig...
Ich LESE offenbar in letzter Zeit zu viele Beiträge eines Netizen namens Zornhau der es LIEBT, wichtige Wörter GROSS zu schreiben :)

Stefan
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

BlackVivi hat geschrieben:(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
Ich finds albern, selbst die Java-Jungs nennen es bei sich call-by-value, obwohl sie ihre Pointer Referenzen nennen. In der Python-Doku steht übrigens auch call-by-value. Aber wenn man sich dann besser fühlt, kann man sich natürlich auch neue Namen dafür ausdenken (so wie man in Java Zeiger Referenzen nennt), auch wenn dann keiner mehr versteht, was man eigentlich meint.

Ich würde ja call-by-implicit-pointer-to-an-object-that-is-passed-by-value vorschlagen ;)
BlackJack

@Darii: Wo steht denn das in der Python-Doku?

Es ist nicht albern, weil man sowohl bei call-by-value als auch bei call-by-reference Erwartungen weckt, die man dann erst wieder ausräumen muss.

Wenn die Java-Jungs (und Mädels) sagen würden, es wären Pointer, aber eben doch wieder nicht so wie das ein C- oder Pascal-Programmierer erwarten würde, bringt das keinen wirklichen Vorteil. Auch wenn sie nicht call-by-sharing oder call-by-object als Begriff sagen würden, müssten sie trotzdem erklären was es ist.

Und call-by-sharing ist kein neuer Begriff, es sei denn 1974 ist für Dich schon zu neu. ;-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dill hat geschrieben:der vorteil ist, dass bei cbv der funktion die variable auf den stack gelegt wird.
Und der Performancevorteil ist jetzt wo? Der Wert muss trotzdem kopiert werden und wenn die Funktion die den Wert bekommt auch noch weitere Funktionen aufruft ist das Objekt letztendlich mehrfach im Stack vorhanden. Ich sehe da also dann zwei Nachteile: mehr Speicherverbrauch und mehr Zeitverbrauch. Natürlich hat es auch einen Vorteil, aber es ist nicht die Performance (oder wir sprechen von negativen Performancevorteilen).
Darii hat geschrieben:
BlackVivi hat geschrieben:(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
Ich finds albern, selbst die Java-Jungs nennen es bei sich call-by-value, obwohl sie ihre Pointer Referenzen nennen. In der Python-Doku steht übrigens auch call-by-value. Aber wenn man sich dann besser fühlt, kann man sich natürlich auch neue Namen dafür ausdenken (so wie man in Java Zeiger Referenzen nennt), auch wenn dann keiner mehr versteht, was man eigentlich meint.
Java hat genausowenig wie Python Zeiger. Es sind Referenzen, aber Referenzen sind keine Pointer. Les dir doch mal die ganzen Threads durch, wo die Leute eine Liste an eine Funktion übergeben, diese verändern und dann das gleiche mit einer Zahl machen und sich wundern, warum sich die zahl außerhalb der Funktion nicht auch geändert hat.

Ich habe anfangs auch den Unterschied zwischen Call-by-Reference und Call-by-Object nicht verstanden, und den Begriff für Überflüssig gehalten, aber wenn man genauer nachdenkt sind es durchaus zwei verschiedene Dinge (ich empfehle in C einen Pointer-to-int zu übergeben und die innerhalb der Funktion zu modifizieren und dann in Python eine Zahl übergeben und das zu modifizieren um sich die Unterschiede klar zu machen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

BlackJack hat geschrieben:@Darii: Wo steht denn das in der Python-Doku?
http://docs.python.org/tutorial/control ... -functions, 5. Absatz, ja ich habe die Fußnote gelesen. Die Konkretisiert aber nur.
Leonidas hat geschrieben:Java hat genausowenig wie Python Zeiger. Es sind Referenzen, aber Referenzen sind keine Pointer.
Java-Referenzen sind Pointer, bloß dass die Sprache die De-/Referenzierung automatisch übernimmt. Ich halte das für eine reine Marketingentscheidung, das Kind Referenz zu nennen. Nicht umsonst gibt es eine „NullPointerException“ in Java. Und Java-„Referenzen“ sind etwas anderes als C++ Referenzen, was dann wirklich call-by-reference ist. Ich halte es da wie beim Duck-Typing, es verhält sich wie ein Pointer, also ist es einer (der Vergleich hinkt ein bisschen). ;)
Ich habe anfangs auch den Unterschied zwischen Call-by-Reference und Call-by-Object nicht verstanden, und den Begriff für Überflüssig gehalten, aber wenn man genauer nachdenkt sind es durchaus zwei verschiedene Dinge (ich empfehle in C einen Pointer-to-int zu übergeben und die innerhalb der Funktion zu modifizieren und dann in Python eine Zahl übergeben und das zu modifizieren um sich die Unterschiede klar zu machen.
Ist vielleicht wirklich besser, dann ist wenigsten klar, was ich meine.
call-by-value(c):

Code: Alles auswählen

#include <stdio.h>

int dummy = 42;
int *bar = &dummy;

void function(int *foobar) {
  foobar = bar; // Ich überschreibe den Wert von foobar
                // dasselbe passiert auch in Java und Python
}

int main(void) {
  int foo = 23;
  printf("foo = %d\n", foo);
  function(&foo);
  printf("foo = %d\n", foo);
  return 0;
}
call-by-reference(c++):

Code: Alles auswählen

#include <cstdio>

int bar = 42;

void function(int &foobar) {
  foobar = bar; 
}

int main(void) {
  int foo = 23;
  printf("foo = %d\n", foo);
  function(foo);
  printf("foo = %d\n", foo);
  return 0;
}
PS: Man habe ich mich beim Schreiben dieser Beispiele wieder über die absolut kryptischen Fehlermeldungen vom gcc gefreut...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Unter Call-by-reference würde ich eher sowas in C verstehen:

Code: Alles auswählen

#include <stdio.h>

int dummy = 42;

void function(int *foobar) {
  *foobar = dummy;
}

int main(void) {
  int foo = 23;
  printf("foo = %d\n", foo);
  function(&foo);
  printf("foo = %d\n", foo);
  return 0;
}
Das Programm würde ich so in Python umsetzen:

Code: Alles auswählen

dummy = 42

def function(foobar):
    foobar = dummy

def main():
    foo = 23
    print "foo = %d" % foo
    function(foo)
    print "foo = %d" % foo
Und hier verhalten sich die zwei Programme durchaus unterschiedlich.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Leonidas hat geschrieben:
Dill hat geschrieben:der vorteil ist, dass bei cbv der funktion die variable auf den stack gelegt wird.
Und der Performancevorteil ist jetzt wo? Der Wert muss trotzdem kopiert werden und wenn die Funktion die den Wert bekommt auch noch weitere Funktionen aufruft ist das Objekt letztendlich mehrfach im Stack vorhanden.
Der Performance-Vorteil liegt in den Vermiedenen Dereferenzierugen. Das lohnt sich natürlich nur bei Daten, welche vom Speicherverbrauch nicht viel größer sind als ein Pointer. Das verursacht dann auch keinen zusätzlichen, oder nur sehr geringen, Mehraufwand im Speicher.
Das Leben ist wie ein Tennisball.
lunar

Die Fußnote nimmt Abstand vom Begriff "call by value" und nennt stattdessen "call by object reference", und ist damit näher am Begriff "call by object", den BlackJack eingeführt hat.

Zeiger sind im Übrigen eine Datentypen, ein "int *foo" ist etwas anderes als "int foo". Eine Referenz dagegen ist kein eigener Datentyp, in Java nicht und auch nicht in C++.

Edit: Im Übrigen läuft die Parameterübergabe an Funktionen nicht notwendigerweise über den Stack.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Leonidas hat geschrieben:Und hier verhalten sich die zwei Programme durchaus unterschiedlich.
Das sind ja auch zwei völlig verschiedene Programme. In dem Python-Program weist du foobar einen neuen Wert zu, in deinem C-Programm weist du dem Speicherbereich auf den foobar zeigt, einen neuen Wert zu, foobar selbst änderst du dabei aber nicht (siehe mein Kommentar in meinem C-Beispiel). C selbst kennt kein call-by-reference, du kannst es aber über Pointer emulieren.
Lunar hat geschrieben:Eine Referenz dagegen ist kein eigener Datentyp, in Java nicht und auch nicht in C++.
Ich hab’s vorhin schonmal angedeutet, Java-Referenzen und C++-Referenzen sind zwei völlig verschiedene Sachen. Java-Referenzen sind mit Watte umhüllte Pointer (sieht man auch am Verhalten des "="-Operators) und C++ Referenzen zeigen auf Variablen.
lunar

Darii hat geschrieben:
Lunar hat geschrieben:Eine Referenz dagegen ist kein eigener Datentyp, in Java nicht und auch nicht in C++.
Ich hab’s vorhin schonmal angedeutet, Java-Referenzen und C++-Referenzen sind zwei völlig verschiedene Sachen.
Das ist mir durchaus klar.
Java-Referenzen sind mit Watte umhüllte Pointer
Sie haben Ähnlichkeiten mit Zeigern, sie sind aber keine Zeiger. Ebenso wie sich Java-Referenzen von C++-Referenzen unterscheiden, unterscheiden sich Java-Referenzen auch von C++-Zeigern. Der Unterschied zwischen den beiden Art von Referenzen ist ihr Verhalten, gemein ist ihnen aber, dass beide keine eigenen Datentypen der jeweiligen Sprache sind. Zeiger dagegen sind ein eigener Datentyp.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

lunar hat geschrieben:Sie haben Ähnlichkeiten mit Zeigern, sie sind aber keine Zeiger.
Was sind sie denn sonst? Java-Referenzen sind ebenso Pointer wie Bäume Pflanzen sind.
Der Unterschied zwischen den beiden Art von Referenzen ist ihr Verhalten, gemein ist ihnen aber, dass beide keine eigenen Datentypen der jeweiligen Sprache sind. Zeiger dagegen sind ein eigener Datentyp.
Das hast du schonmal erwähnt, aber wie kommst du da drauf?
BlackJack

@Darii: Bäume sind keine Pflanzen, sondern eine Datenstruktur. ;-)

Ein Pointer ist in vielen Sprachen ein Datentyp. Man kann Variablen von diesem Typ deklarieren und auch Werte von dem Typ zuweisen, sowie die Operation "dereferenzieren" darauf ausführen. Referenzen dagegen sind kein Datentyp der Sprache Java, sondern ein interner Mechanismus, der auf der Ebene der Implementierung als "klassischer" Pointer umgesetzt wird. Deshalb hat die Sprache Java aber trotzdem keine Pointer. Man könnte sich genauso gut vorstellen, dass alle Objekte als eigene Prozesse modelliert sind, oder eine auf mehrere Rechner verteilte Variante einer JVM verwendet wird, und damit eine Referenz aus mehr als einer simplen Speicheradresse in einem lokalen Prozess besteht. Das sind Implementierungsdetails und keine Spracheigenschaften von Java.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Das sind doch alles Streitereien, die aufgrund unterschiedlicher (und zum Teil falscher) Definitionen entstehen.

Zeiger definiere ich etwa so, dass ich damit eine beliebige Speicherstelle adressieren kann. So etwas hat weder Python noch Java. Dass es dort eine NullPointerException gibt, ist eindeutig ein Benennungsfehler aus der Frühzeit der Sprache, nicht aber ein Indiz dafür, dass Java Zeiger hätte.

Kann man Zeiger auf den Speicher einer Variablen definieren und diese dann (wie in C) an eine Funktion übergeben auf das diese dann den Variableninhalt ändern kann, ist das immer noch kein Call-by-Reference, sondern Call-by-Value. Der Zeiger wird schließlich als Wert übergeben. Erst C++ (oder eben Pascal oder C#) hat CbR.

Was CbR ausmacht, hatte ich schon definiert. CbV ist dementsprechend das Gegenteil. Zuweisungen an Funktionsvariablen (aka Parameter) wirken sich nicht auf die ursprünglichen Variablen aus.

Das alles hat nichts mit dem Kopieren von Objekten zu tun.

CbV, CbR und CbN sagt einzig aus, ob und wie Variablen miteinander "verbunden" sind.

Ich erkenne daher keinen Unterschied zu CbV und Call-by-Object und halte diesen Begriff für unnötig. Wichtig ist nur zu wissen, dass Objekte niemals implizit kopiert werden. Das hat aber (wie gesagt) nicht mit CbR oder CbV zu tun, sondern ist eine Eigenschaft die bereits bei Zuweisung wie "a=b" wichtig ist.

In manchen Sprachen (z.B. C#) unterscheidet man zwischen Werttypen und Referenztypen. Exemplare ersterer werden bei einer Zuweisung kopiert, die anderen eben nicht sondern die neue Variable enthält das selbe Ding wie die alte. In noch exotischeren Sprachen verschwindet sogar das Ding aus er ursprünglichen Variable und Verschieben statt Kopieren ist die Norm, aber das ist hier egal.

All das wird hier laufend durcheinander geworfen.

Python ist dementsprechend eine Sprache, die keine Werttypen kennt. Alles (selbst Zahlen) sind (konzeptionell) Referenztypen. Hatte ich aber schon erwähnt, dass das alles nichts mit CbV und CbR zu tun hat? Python benutzt ausschließlich CbV. Und Python hat keine Zeiger.

Stefan
BlackJack

@sma: Ein Problem dabei ist, dass man dann Werte übergibt, die es für den Anwender gar nicht gibt, denn an den Wert selber, der da übergeben wird, kommt der Anwender nicht heran. Er kommt nur an das übergebene Objekt heran. Also wird aus Anwendersicht das Objekt übergeben, eben call-by-object.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Ich glaube sma hat das ganz gut auf den Punkt gebracht: Was sind überhaupt Pointer? Über eine formale Definition wäre ich froh, aber ich vermute einfach mal es gibt keine.

Ich kann nur festhalten, dass sich Java-Referenzen genau wie C-Pointer verhalten, wobei die De/refenzierung implizit erfolgt. Demnach sind es gemäß Duck-Typing Pointer.

Imho wäre die beste Definition, das Ding nach seinem Zweck zu benennen.

Zeiger: zeigen auf Werte
Referenzen: zeigen auf Variablen

Java-Referenzen zeigen auf Objekte - damit sind es Zeiger
Python-Namen zeigen auf Objekte - damit sind es Zeiger

Ob ich jetzt selbst eine bel. Speicheradresse festlegen darf oder ob ich sie selbst dereferenzieren darf sind imo nur Implementierungsdetails. Je nachdem wie viel man nicht darf, kann man sie ja umbenennen, prinzipiell bleiben es aber Zeiger.
Zuletzt geändert von Darii am Donnerstag 14. Mai 2009, 13:56, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Darii hat geschrieben:Ich glaube sma hat das ganz gut auf den Punkt gebracht: Was sind überhaupt Pointer? Über eine formale Definition wäre ich froh, aber ich vermute einfach mal es gibt keine.
Der englische Wikipedia-Artikel spiegelt das allgemeine Verständnis recht gut wieder.

Edit: Argh, böse Klammern in der URL: http://en.wikipedia.org/wiki/Pointer_(computing)
Das Leben ist wie ein Tennisball.
BlackJack

Java-Referenzen verhalten sich eben nicht wie C-Pointer. Denn bei C-Pointern gibt's keine automatische Dereferenzierung.

Wenn Du sagst Referenzen zeigen auf Variablen, was bitte meinst Du dann mit "Variable"? Eine Variable besteht im Allgemeinen aus einem Namen, einem Typ, einem Wert, und einer Speicheradresse. Ob Typ und Speicheradresse dem Namen oder dem Wert zugeordnet werden, hängt von der Sprache ab. Bei C "hängt" beides am Namen, bei Python am Wert.

Das man selber die Speicheradresse festlegen und selber über's dereferenzieren entscheiden kann, ist für mich genau das Verhalten, was Zeiger ausmacht und kein Implementierungsdetail. Das ist so als wenn man sagen würde, ich habe hier einen Stapel ohne `push()` und `pop()` aber prinzipiell ist's ein Stapel.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

BlackJack hat geschrieben:Wenn Du sagst Referenzen zeigen auf Variablen, was bitte meinst Du dann mit "Variable"?
Guck dir halt mein C++ Beispiel und sag mir wie man das besser formulieren kann. C++ Referenzen kannst du nur Variablen zuweisen nicht die Werte selbst(int &a = 2 geht nicht).
Das man selber die Speicheradresse festlegen und selber über's dereferenzieren entscheiden kann, ist für mich genau das Verhalten, was Zeiger ausmacht und kein Implementierungsdetail. Das ist so als wenn man sagen würde, ich habe hier einen Stapel ohne `push()` und `pop()` aber prinzipiell ist's ein Stapel.
Deswegen habe ich ja nach einer formalen Definition gefragt. „ist für mich genau“ ist jedenfalls keine Definition sondern genau das Problem. Ein Stapel ist hingegen als ADT genau definiert.
BlackJack

Wir reden ja von dem Datentyp, den man meint, wenn man eine Sprache mit Zeigertypen hat. Der Datentyp ist bei C und Pascal zum Beispiel sicher auch irgendwo formal definiert.
Antworten