vorteile einer virtual machine?
-
Ben04 schrieb:
Man beachte bitte, dass viele Vorteile von Java Programmen weder etwas mit Java ansich, noch irgendetwas mit einer VM (wobei letzteres oft sogar ein Nachteil ist) zu tun haben. Java hat eine breitgefecherte Standard Bibliotek und wird auch ansonsten viel von Größen der IT Welt wie Sun gefördert. Das sind die wahren Vorteile von Java. Das gleiche gilt natürlich auch für .net.
...
Desweiteren sind auch Portirungsproblem von C/C++ Programmen von Platform zu Platform oder Compiler zu Compiler ein Nachteil gegenüber Java allerdings kein Nachteil gegenüber einer VM. Wenn jede Java VM ihre eigenen Erweiterungen und ihre eigenen Biblioteken hätte dann würden, trotz VM, die gleichen Probleme herschen wie derzeit in der C/C++ Welt.Viele Sprachen die eine VM haben Vorteile allerdings diese sind in der Regel nicht auf die VM zurück zu führen.
Genau auf den Punkt gebracht. Das ist genau das, was ich meine!
@Optimizer
ich kann nicht nachvollziehen, warum man für Laufzeit-Reflection eine VM braucht. Man könnte auch jede Klasse native in eine .class Datei mit den ganzen Reflection-Informationen (wie Funktionssignaturen, Konstruktoren, etc.) packen. Dann generiert halt der Compiler für jede Klasse eine getClass():Class Methode. Diese Class hat dann die ganzen Reflection-Informationen, die man in Java auch hat. Dann kannste auch "ladeKlasse(dateiname)" aufrufen und mit den ganzen gettern die Informationen aus der .class Datei holen. (öffnet mal mit einem Editor eine .class Datei!)In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Ich bin ehrlich gesagt immer noch nicht von den Vorteilen einer VM überzeugt worden (außer bei den Server- und Applet-Geschichten). Der ganze andere Schnickschnack (Reflection, "SecurityExceptions") könnte meiner Meinung nach auch ohne eine VM realisiert werden.
Ich programmiere gerne in Java, weil es dort einfach eine geile Bibliothek für fast alles gibt.
Allerdings finde ich, dass Java noch erfolgreicher wäre, wenn es dort keine VM gäbe, weil dadurch die Anwendungen viel Speicher fressen und lange Startzeiten durch JIT haben. Die ganzen "Wartungssachen" sind für mich auch wirklich kein Argument. Ich denke jeder Anbieter kann es in Kauf nehmen, für jede Plattform eine native Version zu kompilieren (nicht neu zu schreiben!).
-
mathik schrieb:
@Optimizer
ich kann nicht nachvollziehen, warum man für Laufzeit-Reflection eine VM braucht. Man könnte auch jede Klasse native in eine .class Datei mit den ganzen Reflection-Informationen (wie Funktionssignaturen, Konstruktoren, etc.) packen.Tut mir leid, wenn ich etwas blöd frage: Was ist eine native .class - Datei? Ist das Teil ausführbar? Wenn ja, dann ist es ja fein, und ich muss es nicht mehr zur Laufzeit compilieren. Enthält es alle Reflection-Informationen, die ich brauche? Fein.
Dann generiert halt der Compiler für jede Klasse eine getClass():Class Methode. Diese Class hat dann die ganzen Reflection-Informationen, die man in Java auch hat. Dann kannste auch "ladeKlasse(dateiname)" aufrufen und mit den ganzen gettern die Informationen aus der .class Datei holen. (öffnet mal mit einem Editor eine .class Datei!)
Bedenke dies:
class Base { virtual void methode() = 0; }; int main() { Base* x; cout << "Welche Klasse möchten Sie hinzuladen?"; Class MyDerived; cin >> MyDerived; x = new MyDerived(); // Ich sag jetzt mal, das hat nen Standard-Konstruktor x->methode(); }
Oh verdammt. Das wird jetzt schwierig. Also das MyDerived hast du nicht zur Verfügung, während du main() compilierst. Mit irgendwelchen krassen Datenstrukturen kriegst du das vielleicht noch hin, die Methode dynamisch richtig zu binden. Aber das ist ja nicht das Ende der Fahnenstange.
Jetzt kann ich noch ein paar weitere Klassen hinzuladen. Jedesmal ändert sich die ganze dynamische Bindung. Das x->methode(); kann nach jedem hinzuladen einen anderen Effekt haben. Jedesmal muss sich das Verhalten von dynamic_cast und typeid() ändern. Und das Ganze ohne Neucompilierung des Hauptprogramms. Selbst wenn du das noch sauber hinkriegst, bist du jetzt schon um Längen inperformanter als Java, was einfach neu compiliert und immer noch völlig simpel dynamisch bindet. Und jetzt gehen die Probleme erst los.
Jetzt schaut dann die .class Datei so aus:
class Derived : Base { void foo(); };
Und ich stelle fest, ja, die implementiert gar nicht meine abstrakte Methode. Das gibt Ärger. Du hast keine Möglichkeit, dass zur Kompilierzeit festzustellen, musst jetzt in dein Programm also nen halben Compiler einbauen, um zur Laufzeit festzustellen, ob das dann überhaupt geht. Damit ist es schon fraglich, ob du dich jetzt überhaupt an meine kleine Einschränkung gehalten hast, die da lautete, keine JIT-Compiler in das Programm einzubauen.
Das Ganze kann noch unendlich viel komplizierter werden, wenn Mehrfachvererbung hinzukommt. Vergiss auch nicht, dass du durch das hinzuladen neuer Klassen, vorhandenen, eigentlich statischen Code ändern musst.
class Fraction { // Implementiert nicht op<< aber ein op(double) }; int main() { Type type; ... // Klasse Fraction laden Type* a new Type(5, 2); cout << *a; // Gibt ein double aus. }
Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Ne, ich bin ja eigentlich schon fast geneigt zu sagen, dass die Sprache C++ schon an sich fast zu kompliziert für solche Späße ist. Aber dann ohne JIT-Compiler noch... kann ich mir nicht vorstellen.
In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Rate mal, wieso.
Ich bin ehrlich gesagt immer noch nicht von den Vorteilen einer VM überzeugt worden (außer bei den Server- und Applet-Geschichten). Der ganze andere Schnickschnack (Reflection, "SecurityExceptions") könnte meiner Meinung nach auch ohne eine VM realisiert werden.
Kann jeder zu stehen wie er will. Ich sehe in einer VM viele Vorteile und Nachteile, die allesamt im Laufe der Zeit behoben werden könnten. Ist aber nicht meine Absicht, dich zu überzeugen. Ich will dir nur zeigen, dass es Dinge gibt, die ohne VM nicht gehen, was ja der Topic war.
Ich programmiere gerne in Java, weil es dort einfach eine geile Bibliothek für fast alles gibt.
Allerdings finde ich, dass Java noch erfolgreicher wäre, wenn es dort keine VM gäbe, weil dadurch die Anwendungen viel Speicher fressen und lange Startzeiten durch JIT haben.Vielleicht bist du noch nicht tief genug in Java eingestiegen. Ein paar wirklich geile Features, wegen den unter anderem Java so geschätzt wird, sind ohne VM nicht möglich. Das geht schon los beim dynamischen Laden von Datenbank-Treibern *an mein Praktikum mit Schaudern denk*.
Du musst Java so nehmen wie es ist und ich finde es gut so.
-
Optimizer schrieb:
Kann der Compiler alles in den VTable packen.
Genau, für Klassen, die er kennt, kann er das tun. Aber nicht für Klassen, die erst zur Laufzeit hinzugeladen werden.[/quote]
Und die DLL wurde etwa nicht von Compiler übersetzt? Es ist ja nicht so, dass alle VTables in der exe Datei liegen müssen.Optimizer schrieb:
Höh? Du weißt doch zur Compilierzeit noch nicht mal, was die Klasse des zu erstellenden Objekts für Konstruktoren hat. Da bin ich ja mal gespannt. Wie du ohne JIT-Compilierung dann noch eine Factory erstellen kannst.
Für jede Klasse generiert der Compiler eine Funktion die eine Instance dieser Klasse erstellt. Nun legt er eine Map die den Namen der Klasse mit der Funktion assoziirt. Wenn du nun eine Dll lädst hat diese auch so eine Map. Während des Laden müssen sie nur zusammen gefügt werden.
Optimizer schrieb:
Hier kann man allerdings auch noch ein wenig optimiren indem man, nachdem man das erste mal den Namen nachgeschlagen hat, den Funktionsaufruf während der Laufzeit überschreiben um dann nächstes mal direkt die richtige Funktion aufzurufen. Der Compiler muss nur genügend NOPs während der Übersetzung reinpacken damit keine Sprünge durcheinander kommen. Wenn die Anzahl der Parameter bekannt ist, ist das auch kein Problem. Fals die Anzahl nicht bekannt ist kann man ein Arraypointer übergeben.
Wie, wo was? Der Compiler kann zur Laufzeit in deinem Fall nichts mehr machen. Du kannst nur Methoden aufrufen
- deren Name du zur Compilierzeit kennst
- deren Signatur du zur Compilierzeit kennstWer sagt, dass nur der Compiler ist der Code schreibt? Das Program kann ja selber an sich umschreiben.
In etwa so hatte ich mir das vorgestellt (Pseudo ASM)
loopup_name: pop eax ;Schlag Funktions Pointer nach und pack ihn in eax ;Generire den Code um die Funktion in eax aufzurufen und speicher ihn in eax pop ebx mov [ebx] eax pop eax ;füll alles von [eax] bis [ebx] mit NOPs auf jmp ebx ;Irgendwo im Code schreib_von: push schreib_bis push schreib_von push name jmp lookup_name nop nop schreib_bis:
Natürlich muss hierführ das Program schreibenden Zugriff auf seinen Code haben. Wenn das nicht der Fall ist, bleibt noch die Möglichkeit einen statischen Funktionspointer einzusetzen. Der Compiler setzt ihn auf loopup_name und diese Funktion setzt ihn dann auf etwas anderes. Da der Aufruf ja über einen Funktionspointer stattfindet kann man den Aufruf jeder Zeit woanders enden lassen.
Optimizer schrieb:
Du hast erstmal keine VTable und kannst sie erst zur Laufzeit erstellen, weil du vorher die Klassendefinition nicht hast. Du brauchst immer irgendein für deine Fälle angepasstes Format, oder von mir aus auch eins, was sehr flexibel ist, aber trotzdem wirst du nicht Klassen von anderen einfach reinladen können, wenn die anderen UND du dafür nicht spezielle Dinge vereinbaren.
Da bin ich ganz deiner Meinung, allerdings wie bereits gesagt kann man auch VTables aus einer DLL nachladen und in eine VTable kann sämtliche Informationen über einen Type speichern die bei der Übersetzung bekannt sind.
mathik schrieb:
Die ganzen "Wartungssachen" sind für mich auch wirklich kein Argument. Ich denke jeder Anbieter kann es in Kauf nehmen, für jede Plattform eine native Version zu kompilieren (nicht neu zu schreiben!).
Mit make ähnlichen Tools muss der Anbieter noch nicht mal nativ Versionen anbieten. Man müsste sich auf eine einheitlich Sprache einigen in der man Anwendungen verbreitet, das kann auch soetwas wie Java Bytecode. Dann stellt jedes OS ein Tool zur Verfügung mit der man den Code in nativ Code übersetzt und ganz nebenbei das Program auch noch installiert. Man hat somit sämtliche Vorteile der Wartbarkeit jedoch keine Nachteile der VM. Daus werden sich die Funktionsweise die heutigen Windows Installationsprogrammen ähnelt mit Sicherheit freuen. Man muss ihnen ja nicht sagen, dass der Compiler läuft, also machen sie sich auch keinen Kopf dadrüber
.
Optimizer schrieb:
class Base { virtual void methode() = 0; }; int main() { Base* x; cout << "Welche Klasse möchten Sie hinzuladen?"; Class MyDerived; cin >> MyDerived; x = new MyDerived(); // Ich sag jetzt mal, das hat nen Standard-Konstruktor x->methode(); }
Oh verdammt. Das wird jetzt schwierig. Also das MyDerived hast du nicht zur Verfügung, während du main() compilierst. Mit irgendwelchen krassen Datenstrukturen kriegst du das vielleicht noch hin, die Methode dynamisch richtig zu binden. Aber das ist ja nicht das Ende der Fahnenstange.
Also ich sehe die Schwierigkeit nicht? Wie bereits oben gesagt braucht der Compiler nur eine map<string, void*(*)(...)> in die EXE und in die DLL zu packen. Beim laden der Dll werden dann beide zusammen gefügt. Dann muss der Compiler aus
x = new MyDerived();
nur ein
x = constructor_map["MyDerived"];
machen. Vielleicht noch ein paar Tests machen, wie zum Beispiel ob so eine Klasse geladen ist und ob sie auch von Base erbt und dann wenn nötig eine Exception werfen.
Das einzige was nicht geht ist eine dynamisch hinzugeladene Klasse auf den Stack zu packen. Aber wofür gibt es std::auto_ptr? Einfach unter die Compilerhaube und der Programmierer wird es nie merken. MS macht das auch so in C++/CLI.
Allerdings frag ich mich wirklich wo du soetwas brauchen willst? Jedes Pluginsystem ist anders und ich kann mir nicht vorstellen, dass du mit einem so allgemeinem Anstatz glücklich wirst.
Optimizer schrieb:
Jetzt kann ich noch ein paar weitere Klassen hinzuladen. Jedesmal ändert sich die ganze dynamische Bindung. Das x->methode(); kann nach jedem hinzuladen einen anderen Effekt haben. Jedesmal muss sich das Verhalten von dynamic_cast und typeid() ändern.
Alte Klasse aus der Map rauswerfen und neue hinzufügen. dynamic_cast mit Hilfe einer virtuellen is_castable(type_info&) Methode implementiren. typeid spiegelt nur Laufzeit Informationen. Allerdings wenn du soetwas brauchst musst du nur eine zweite Map anlegen und dann nach gleichen Schema vorgehen wie um ich es bei der Erschaffung der einer Instance gezeigt habe.
Optimizer schrieb:
Und das Ganze ohne Neucompilierung des Hauptprogramms.
Würd ich auch nicht wollen. Wenn man erst am Code rumschreiben geht, dann wird es erst kompliziert. Ist aber alles machbar.
Optimizer schrieb:
Selbst wenn du das noch sauber hinkriegst, bist du jetzt schon um Längen inperformanter als Java, was einfach neu compiliert und immer noch völlig simpel dynamisch bindet. Und jetzt gehen die Probleme erst los.
Ich sehe nicht wieso das mit einer VM so performant sein soll. Das Nachschlagen in einer Map ist nicht langsam und wie oben gezeigt muss man es ja nur einmal tun. Unter Java ist das ja auch nicht kostenlos, der Code muss neu überstetz werden und wenn man dann noch optimiert sind das zwar einmalige Kosten aber sehr große in der das gesamte Program einfriert. Oder willst du das ganze threadsafe machen? Also in dem einen Thread läuft der Compiler und in einem anderen wird auf Eingaben des Users reagiert. Und was ist mit Instancen von Klassen die es nach dem neu kompilieren gar nicht mehr gibt? Was mit Funktionspointern (wenn es sowas in Java gibt) die nun ins Leere zeigen? Also ich glaub nicht, dass das so einfach geht wie du dier das vorstellst. Bitte um Aufklärung.
Optimizer schrieb:
class Fraction { // Implementiert nicht op<< aber ein op(double) }; int main() { Type type; ... // Klasse Fraction laden Type* a new Type(5, 2); cout << *a; // Gibt ein double aus. }
Ich gehe mal davon aus, dass dieses "Type" eigentlich ein "Fraction" sein soll und zwischen "a" und "new" noch ein "=" gehört.
Optimizer schrieb:
Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Das Zauberwort heist double Dispatching. Und man kann jeden buildin Operator auch durch einen Funktionsaufruf ersetzen.
Sebst Templates kannst mit einer nachgeladenen Klasse spezialisieren. Man braucht zunächst wieder eine Map die den Namen der Klasse als Schlüssel hat. Jetzt schlägt man einen Klassen VTable mit sämtlichen Methoden der Klasse nach. Alles was kein Operator muss wieder in einer weiteren Map nachgeschlagen werden. So nun spezialisert der Compiler während des Übersetzen für einen Type der alle Methoden und Operatoren auf so ein Klassen VTable umlenkt. Wenn du willst kannst du auch den compilierten Template Code kopieren und dann die Funktionsaufrufe wie oben gezeigt nachschlagen. Du erhälst zwar keinen Code der bis in den letzten Winkel micro optimiert ist allerdings ganz brauchbar ist und das viel schneller als wenn du den Code neuübersetzrn würdest.
Optimizer schrieb:
In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Rate mal, wieso.
Hmm, vielleicht weil es viel Arbeit ist und wenig bringt? So in etwa wie mit export.
Meiner Meingung nach ist es Schwachsinn auf das statische Interface dynamisch zurück greifen zu wollen. Reflexion ist nützlich solang es dazu diehnt Klassen zu benutzen von denen man nur die Basisklasse kennt, hier nimmt es einem zum Beispiel ab das Factory Pattern implementiren zu müssen. Allerdings sobald man auf Funktionen zurückgreifen will deren Existenz du während der Übersetzung noch nicht mal ansatzweise geahnt hat, dann hast du ein dickes Denkproblem. Sollten solche Machenschaften bei Java die Regel sein (wovon ich nicht ausgehe), dann fange ich an zu verstehen wieso soviele Leute Java hassen.
-
Ben04 schrieb:
Optimizer schrieb:
class Fraction { // Implementiert nicht op<< aber ein op(double) }; int main() { Type type; ... // Klasse Fraction laden Type* a new Type(5, 2); cout << *a; // Gibt ein double aus. }
Ich gehe mal davon aus, dass dieses "Type" eigentlich ein "Fraction" sein soll und zwischen "a" und "new" noch ein "=" gehört.
Die zweite Annahme ist korrekt, die erste nicht. Es soll ja wirklich ein beliebiger Typ erstmal sein, mit Konstruktor(int, int).
Optimizer schrieb:
Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Das Zauberwort heist double Dispatching. Und man kann jeden buildin Operator auch durch einen Funktionsaufruf ersetzen.
Du ignorierst völlig, worauf ich hinauswollte. Es geht darum, dass das Nachladen einer Klasse zur Laufzeit das Verhalten von bereits vorhandenem Code ändern kann.
Aber das ist ja für dich kein Problem:
Wer sagt, dass nur der Compiler ist der Code schreibt? Das Program kann ja selber an sich umschreiben.
Vielleicht noch ein paar Tests machen, wie zum Beispiel ob so eine Klasse geladen ist und ob sie auch von Base erbt und dann wenn nötig eine Exception werfen.
Und so lange du nicht anerkennst, dass du mit sowas einen halben Compiler in dein Programm einbaust, wirst du kein Problem damit haben.
Ein "paar Tests" beinhaltet ja vermutlich auch das Prüfen auf mehrdeutige Aufrufe, insbesondere im Zusammenhang mit Mehrfachvererbung ebenso wie in Kombination mit Templates und anderen extrem komplizierten Tests, die auch die statischen Compiler noch nicht seit langem alle standardkonform durchführen.Du unterschätzt das Problem. Das Problem ist, dass du dich auf nichts mehr verlassen kannst. Während cout << a; im ersten Moment noch eine Memberfunktion operator(double) aufrufen kann, kann es im nächsten Moment schon eine globale Funktion sein. Das kannst du nicht mit irgendwelchen Datenstrukturen so toll flexibel gestalten, dazu musst vorhandenen, bereits compilierten Code wieder ändern. Und das macht dein Programm, was einen halben Compiler in sich hat, natürlich auch.
Und die DLL wurde etwa nicht von Compiler übersetzt? Es ist ja nicht so, dass alle VTables in der exe Datei liegen müssen.
Das hab ich ja nicht gesagt. Aber du kannst trotzdem nicht die VTable in die DLL flacken und dann dynamisch hinzuladen, weil die VTable in die Umgebung passen muss, in die sie hineingeladen wird.
Wenn du die Basisklasse A mit einer abstrakten Methode hast und B implementiert sie, dann lädst du C : B dynamisch hinzu. Wie sieht die VTable von C aus? Richtig, C muss die Methode von B nehmen. Wenn jetzt aber A die Methode implementiert und B sie nicht redefiniert, muss C die Methode von A nehmen. C kennt A und B zu seiner Kompilierzeit nicht, weil das die schnucklige Klasse ist, die ich seperat erstellen und in meine DLL tun will. Du kannst die VTable nicht erstellen, ohne das Umfeld zu kennen.Ich sehe nicht wieso das mit einer VM so performant sein soll. Das Nachschlagen in einer Map ist nicht langsam und wie oben gezeigt muss man es ja nur einmal tun. Unter Java ist das ja auch nicht kostenlos, der Code muss neu überstetz werden und wenn man dann noch optimiert sind das zwar einmalige Kosten aber sehr große in der das gesamte Program einfriert. Oder willst du das ganze threadsafe machen? Also in dem einen Thread läuft der Compiler und in einem anderen wird auf Eingaben des Users reagiert.
Wenn du keine Annahmen machst, kannst du nichts optimieren. Völlig klar. Wenn ich in Java ne Klasse hinzulade und dann neu kompilieren kann, kann ich die neuen Annahmen nutzen. Ein paar Teile kann man sicher auch ohne JIT-Compiler implementieren, die du dann aber extrem flexibel halten musst. Und viele Teile gehen gar nicht, wie oben beschrieben.
Das mit den Threads ist überhaupt kein Problem (in C++ auch nicht, da gibt's das ja nicht). Dazu muss man nur wissen, wie der JIT-Compiler überhaupt aufgerufen wird. Das geht meistens über ein paar mark-Bits, ob die Funktion schon compiliert wurde, oder auch über nen Funktionszeiger, der dann nicht auf die Funktion zeigt, sondern auf eine Routine, die den JIT aufruft. Wenn das mehrere Threads machen, fangen sie sich halt alle darin und sind blockiert. Dass Threads blockiert sind, die gerade eine zu compilierende Funktion aufrufen, ist ja auch klar. Die anderen können aber weiterlaufen.
Wie auch immer, wenn ich ne Klasse hinzulade, muss ich eigentlich nur ein paar Bits/Zeiger zurücksetzen und sonst läuft alles weiter wie bisher. Sobald die Funktion wieder aufgerufen wird, ist sofort klar, dass sie neu compiliert werden muss. Die Kunst ist höchstens noch, zuverlässig die Funktionen zu bestimmen, die neu compiliert werden müssen. Beim maximalen Nerv-Faktor setz ich halt alle zurück.Allerdings sobald man auf Funktionen zurückgreifen will deren Existenz du während der Übersetzung noch nicht mal ansatzweise geahnt hat, dann hast du ein dickes Denkproblem. Sollten solche Machenschaften bei Java die Regel sein (wovon ich nicht ausgehe), dann fange ich an zu verstehen wieso soviele Leute Java hassen.
Nein, das ist einfach nur dein Denkproblem. Es gibt Sachen, die möchte man an manchen Stellen so flexibel halten und das bricht dir jetzt nur ohne JIT-Compilierung das Genick, weshalb du es nicht magst :p . Wozu sollte Reflection gut sein, wenn ich schon weiß, was das Teil für Methoden hat?
Natürlich wird man sich ab und zu was dabei denken. Man wird sagen, mich interessieren die setter und getter und die haben sich an eine bestimmte Namenskonvention zu halten. Das wird z.B. bei Beans und JSP-Custom-Tags so gehandhabt. Prinzipiell kann aber alles auf einen zukommen.
-
also ich hab den beitrag zwar nicht 100%ig verfolgt,
will aber trotzdem mal meinen senf dazu abgebenich programmiere viel mit c++ und c#. die reflection
ist zwar ohne zweifel ein maechtiges werkzeug, dennoch
sollte man das ganze nicht in den himmel loben.durch die reflection geht die ganze zur compilierzeit
moegliche typ sicherheit verloren.wenn du plugins laedts wuerde ich das ueber eine klassen
schnittstelle machen nicht ueber reflection.wird zuviel mit reflection gearbeitet verhaelt sich der code
eher wie eine typenlose skriptsprache wie javascript, php etc.
wo du erst zur ausfuerhrungszeit merkst, dass es methode xyz
fuer klasse abc gar nicht gibt.deshalb: reflection is ne super sache aber nur einsetzen,
wenn alle anderen methode nicht anwendbar sind.
-
Optimizer schrieb:
Und so lange du nicht anerkennst, dass du mit sowas einen halben Compiler in dein Programm einbaust, wirst du kein Problem damit haben.
Jeder virtuelle Aufruf kann das Verhalten von altem Code beeinflussen, sogar brechen, und wenn oft genug eingesetzt völlig verändern. Wenn du jeden virtuelle Aufruf als Minicompiler bezeichnest, und jeden Minicompiler als VM dann sagst du, dass selbst ASM einen VM hat da man ja mit Hilfe von Funktionspointer einen virtuellen Aufruf machen kann. Ich habe ja auch eine alternative, leicht imperformatere Lösung gegeben die nicht am Code rumschreiben geht.
Als Compiler bezeichne ich etwas das den bereits existirenden Code wegwirft und den Sourcecode (oder auch Bytecode) neu übersetzt. Das ist bei meinem Ansatz aber keineswegs der Fall.
Optimizer schrieb:
Ein "paar Tests" beinhaltet ja vermutlich auch das Prüfen auf mehrdeutige Aufrufe, insbesondere im Zusammenhang mit Mehrfachvererbung ebenso wie in Kombination mit Templates und anderen extrem komplizierten Tests, die auch die statischen Compiler noch nicht seit langem alle standardkonform durchführen.
Du kommst vom Thema ab, das sind alles Problem die sich von der Sprache C++ her ergeben und haben nichts mit einer VM zu tun. Allerdings werde ich trotzdem auf deine Aussage eingehen.
Mehrdeutige Aufrufe entstehen dadurch, dass der Type des übergebenem Werts nicht dem des Parameters entspricht und es mehere Verwandlungsmöglichkeiten gibt. Wenn jede Klasse virtuelle Verwandlungsoperatoren mit bring und jede Funktion die ihr Verhalten ändern kann nach allen Parametern dispatcht wird, ist das Problem gelöst. Natürlich wäre es besser sämtliche implicite Verwandlungen abzuschaffen.
Wenn du darauf hinaus willst, dass sich Klassenhierarchien verändern können und deshalb das Verhalten von dynamic_cast sich verändert, dann siehst du nicht was mit klassenweiten virtuellen Funktion möglich ist. Jede Klasse kriegt eine is_castable Funktion, diese baut dann auf der Funktion ihrer Eltern auf. Ändern die Eltern ändert sich das Verhalten. Das einzige was durchaus zum Problem werden könnte sind Crosscasts, aber da Java ja eh keine Mehrfachvererbung hat.
Optimizer schrieb:
Das hab ich ja nicht gesagt. Aber du kannst trotzdem nicht die VTable in die DLL flacken und dann dynamisch hinzuladen, weil die VTable in die Umgebung passen muss, in die sie hineingeladen wird.
Hier wäre es viellecht interessant mich selbst zu zitieren
ben04 schrieb:
Ich seh da nichts was übermässig schwer mit nativ Code zu machen wäre, natürlich nur mit ein wenig Unterstüzung des Compilers und kompatiblen ABIs.
Und, dass dies nicht der Fall ist, ist ein Vorteil von Java und nicht einer VM, wie ich auch bereits gesagt habe.
Nein, das ist einfach nur dein Denkproblem. Es gibt Sachen, die möchte man an manchen Stellen so flexibel halten und das bricht dir jetzt nur ohne JIT-Compilierung das Genick, weshalb du es nicht magst :p .
Na wenn du das sagst.
Irgenwie klingt mir das nach Machenschaften wie:
int foo1=3; int foo2=1; int foo3=4; int foo4=2; int a=2; int b; execute_code("b = foo%i", a);
Ich hab vor ein paar Jahren sehr oft mit einer interpretierten Sprache gearbeitet, die soetwas erlaubt hat. Meine Erinnerungen daran sind durchgehend schlecht und dabei denke ich noch nicht einmal an all die Sicherheitslücken die sich damit bei so einem Pluginsystem reihenweise auftun.
Desweitern ist dein Pluginsystem auch bei weitem nicht annähernt so flexibel wie du dir das vorstellst. Bedenke jede Klasse ist global zugänglich und somit hat
Base*a=new MyLoadedClass;
alle Probleme die mit globalen Variablen zusammenhängen. Du kannst bespielsweise nur ein Plugin zur gleichen Zeit laden. Was das für Probleme bei Pluginsystem wie zum Beispiel von Firefox mit sich bringt brauch ich ja wohl nicht zu erklären.
Wozu sollte Reflection gut sein, wenn ich schon weiß, was das Teil für Methoden hat?
Ja eben, darauf will ich hinaus. Und wenn du
MyLoadedClass*a = new MyLoadedClass; a->foo();
schreibst dann weist du ja, dass es die Klasse MyLoadedClass gibt und, dass sie eine Methode foo hat. Also wieso nicht gleich:
typedef Base*(*Func)(); Func create = (Func)GetProcAddress(..., "CreateMyLoadedClass"); Base*a = create(); a->foo();
Der Syntax ist vielleicht nicht schön aber der hat ja nichts mit einer VM zu tun. Allerdings ist die zweite Version flexibler als die erste. In der ersten kann es nur eine MyLoadedClass geben. In der Zweiten kann man problemlos mehrere DLLs laden und dann das jeweilige "CreateMyLoadedClass" laden.
Wie bereits gesagt mit solch einem allgemeinem Ansatz wirst du nicht glücklich werden.
-
Ben04 schrieb:
Optimizer schrieb:
Und so lange du nicht anerkennst, dass du mit sowas einen halben Compiler in dein Programm einbaust, wirst du kein Problem damit haben.
Jeder virtuelle Aufruf kann das Verhalten von altem Code beeinflussen, sogar brechen, und wenn oft genug eingesetzt völlig verändern. Wenn du jeden virtuelle Aufruf als Minicompiler bezeichnest, und jeden Minicompiler als VM dann sagst du, dass selbst ASM einen VM hat da man ja mit Hilfe von Funktionspointer einen virtuellen Aufruf machen kann. Ich habe ja auch eine alternative, leicht imperformatere Lösung gegeben die nicht am Code rumschreiben geht.
Als Compiler bezeichne ich etwas das den bereits existirenden Code wegwirft und den Sourcecode (oder auch Bytecode) neu übersetzt. Das ist bei meinem Ansatz aber keineswegs der Fall.
Doch! Muss ich jetzt zum dritten mal dieses Beispiel hier erwähnen?
int main() { Type type; ... // Klasse laden Type* a = new Type(5, 2); cout << *a; }
Hier ist überhaupt nichts mit dynamischer Bindung. N.I.C.H.T.S.
Type könnte nen op<< implementieren. Der ist schon mal global und wird mit Sicherheit nicht dynamisch gebunden. Type könnte aber auch keinen op<< implementieren, sich aber dafür implizit in was umwandeln lassen, was den op<< implementiert. Sense. Nix dynamische Bindung. Du musst die main-Funktion neu compilieren, wenn du nen anderen Typen hast. Es gibt keinen Weg drum herum.Wenn jede Klasse virtuelle Verwandlungsoperatoren mit bring [...]
*lol* in jeden Typ, auch die man dynamisch hinzulädt, oder?
Natürlich wäre es besser sämtliche implicite Verwandlungen abzuschaffen.
Das einzige was durchaus zum Problem werden könnte sind Crosscasts, aber da Java ja eh keine Mehrfachvererbung hat.
Deshalb meine Aussage, für C++ ist sowas mit JIT-Compiler schon schwer genug.
Optimizer schrieb:
Das hab ich ja nicht gesagt. Aber du kannst trotzdem nicht die VTable in die DLL flacken und dann dynamisch hinzuladen, weil die VTable in die Umgebung passen muss, in die sie hineingeladen wird.
Hier wäre es viellecht interessant mich selbst zu zitieren
ben04 schrieb:
Ich seh da nichts was übermässig schwer mit nativ Code zu machen wäre, natürlich nur mit ein wenig Unterstüzung des Compilers und kompatiblen ABIs.
Und, dass dies nicht der Fall ist, ist ein Vorteil von Java und nicht einer VM, wie ich auch bereits gesagt habe.
Hallo? Was hat das bitte damit zu tun? Ich sage:
Wenn du dynamisch Klassen hinzulädst, muss du die VTable zur Laufzeit erstellen. Begründung mit Beispiel im vorherigen Post. Da nützt dir irgendein zauberhafte kompatibles API gar nichts. Da nützt dir nur ein Compiler"-ähnliches" Werkzeug was.So lange du nicht auf diesen beiden Punkte mit ihren Beispielen konkret eingehst, nehme ich dir beim besten Willen nicht ab, dass dynamisches hinzuladen von Klassen und die damit verbundene Laufzeit-Reflection ohne JIT-Compiler möglich ist.
Irgenwie klingt mir das nach Machenschaften wie: [...]
Du kannst immer genügend Beispiele finden, wo sowas Nachteile hat. Tatsache ist: Es ist manchmal nützlich und es wird manchmal angewendet. Egal, ob du es magst. Ich möchte auch eigentlich gar nicht jetzt feststellen ob Reflection toll ist oder nicht. ^^ Topic
-
Optimizer schrieb:
Vergiss auch nicht, dass du durch das hinzuladen neuer Klassen, vorhandenen, eigentlich statischen Code ändern musst.
C/C++ Code:
class Fraction
{
// Implementiert nicht op<< aber ein op(double)
};int main()
{
Type type;
... // Klasse Fraction ladenType* a new Type(5, 2);
cout << *a; // Gibt ein double aus.
}
C/C++ Code:
class Fraction
{
// Implementiert nicht op<< aber ein op(double)
};int main()
{
Type type;
... // Klasse Fraction ladenType* a new Type(5, 2);
cout << *a; // Gibt ein double aus.
}
C/C++ Code:
class Fraction
{
// Implementiert nicht op<< aber ein op(double)
};int main()
{
Type type;
... // Klasse Fraction ladenType* a new Type(5, 2);
cout << *a; // Gibt ein double aus.
}Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Ne, ich bin ja eigentlich schon fast geneigt zu sagen, dass die Sprache C++ schon an sich fast zu kompliziert für solche Späße ist. Aber dann ohne JIT-Compiler noch... kann ich mir nicht vorstellen.
wenn ich eine DLL lade, brauch ich keine VM dafür und ich brauche auch nicht den statischen code zu ändern!
Es könnte doch in C++ genauso wie in Java realisiert werden:
//Diese Klasse ist in einer "CDLL (Class DLL)" //in einer Class DLL sind alle reflection infos im gleichen format wie in einer .class datei von java, nur im native code class MeineDynamischeKlasse { int x; public: MeineDynamischeKlasse(int a): x(a) {} int f(int b) { cout << "hallo " << x << b; } } public static void main() { //lade MeineDynamischeKlasse dynamisch nach // alle reflection infos mit den dazugehörigen adressen werden jetzt aus der CDLL geladen und in "dynamischeKlasse" gepackt. Class* dynamischeKlasse = Class::forName("MeineDynamischeKlasse"); //hole konstruktor mit dem parameter "int" Constructor* standardKonstruktor = dynamischeKlasse->getConstructor(Class::forName("int")): //hole die Methode "f" Method* fMethode = dynamischeKlasse->getMethod("f", Class::forName("int")); //erzeuge jetzt ein objekt vom typ MeineDynamischeKlasse und übergebe konstruktor die 10 Object* obj = standardKonstruktor->newInstance(10); //rufe die methode "f" auf. auf der konsole sollte jetzt "hallo 10 20" ausgegeben werden fMethode->invoke(obj, 20); }
das ist doch "Laufzeit-Reflection", oder? Wo muss man hier den bestehenden statischen Code ändern? Hier werden überall nur Zeiger bzw. Referenzen verwendet!
was du dort gepostet hast, mit dem << operator. sowas ist mit java reflection auch nicht möglich!
-
Wo muss man hier den bestehenden statischen Code ändern? Hier werden überall nur Zeiger bzw. Referenzen verwendet!
Ja, was ist hier? Dein Code jetzt? Super!
Und was ist mit meinem, legalen, standardkonformen C++ Code?was du dort gepostet hast, mit dem << operator. sowas ist mit java reflection auch nicht möglich!
Doch. Ich kann auch statische Funktionen (wie der operator<< eine wäre) mit Reflection getten und aufrufen.
-
Komisch, ich verstehe das Problem gar nicht. Ich sag ja nicht mal, dass man sowas unbedingt braucht. Ich sag auch nicht, dass es toll ist (auch wenn ich es trotztdem toll finden darf). Die Frage war doch nur "wofür braucht man ne VM", worauf ich sage, für JIT-Compilierung, außer ich bau nen Compiler in meine .exe ein, was natürlich Unsinn ist.
Das kann man doch akzeptieren, oder?
-
Optimizer schrieb:
Wo muss man hier den bestehenden statischen Code ändern? Hier werden überall nur Zeiger bzw. Referenzen verwendet!
Ja, was ist hier? Dein Code jetzt? Super!
Und was ist mit meinem, legalen, standardkonformen C++ Code?Dein Code sieht schön und einfach aus. Ich kann nachvollziehen, dass man dafür einen JIT braucht.
Allerdings ist dort die ganze Typprüfung futsch! Nicht mal in Java funktioniet das so einfach, und unsicher! Dort musst du dir alles schön selber über die Class besorgen! (siehe Beitrag oben)was du dort gepostet hast, mit dem << operator. sowas ist mit java reflection auch nicht möglich!
Doch. Ich kann auch statische Funktionen (wie der operator<< eine wäre) mit Reflection getten und aufrufen.[/quote]
globale Funktionen gibt es bei Java nicht.
BTW: es geht mir nicht darum, dass wir uns hier jetzt für C++ eine Reflection-API ausdenken. Mag seien, dass man für C++-reflection einen JIT benötigen würde. Will mir da auch echt kein Kopf drüber machen...
Meiner Meinung nach ist für Java-Reflection keine VM oder auch JIT notwendig.
-
Optimizer schrieb:
Komisch, ich verstehe das Problem gar nicht. Ich sag ja nicht mal, dass man sowas unbedingt braucht. Ich sag auch nicht, dass es toll ist (auch wenn ich es trotztdem toll finden darf). Die Frage war doch nur "wofür braucht man ne VM", worauf ich sage, für JIT-Compilierung, außer ich bau nen Compiler in meine .exe ein, was natürlich Unsinn ist.
Das kann man doch akzeptieren, oder?Wofür braucht man JIT Compilierung, bei Java?
Ich denke, für Reflection nicht....Evtl. fürs dynamische Optmieren? Wenn ja, bringt das wirklich so viel?
-
mathik schrieb:
Optimizer schrieb:
Wo muss man hier den bestehenden statischen Code ändern? Hier werden überall nur Zeiger bzw. Referenzen verwendet!
Ja, was ist hier? Dein Code jetzt? Super!
Und was ist mit meinem, legalen, standardkonformen C++ Code?Dein Code sieht schön und einfach aus. Ich kann nachvollziehen, dass man dafür einen JIT braucht.
Allerdings ist dort die ganze Typprüfung futsch! Nicht mal in Java funktioniet das so einfach, und unsicher! Dort musst du dir alles schön selber über die Class besorgen! (siehe Beitrag oben)
Klar. Das dynamische hinzuladen von Klassen hat Nachteile und Einschränkungen, das stand ja nie in Frage.
was du dort gepostet hast, mit dem << operator. sowas ist mit java reflection auch nicht möglich!
Doch. Ich kann auch statische Funktionen (wie der operator<< eine wäre) mit Reflection getten und aufrufen.
globale Funktionen gibt es bei Java nicht.
Man, jetzt bitte.
"(wie der operator<< eine wäre)". Nimm halt dann C#. Da kannst Operatoren schreiben. Der muss nicht außerhalb einer Klasse stehen. Er ist nicht Member und wird nicht dynamisch gebunden, das ist der Punkt. Und nicht, ob's global oder statisch ist. Sowas langweilt doch.BTW: es geht mir nicht darum, dass wir uns hier jetzt für C++ eine Reflection-API ausdenken. Mag seien, dass man für C++-reflection einen JIT benötigen würde. Will mir da auch echt kein Kopf drüber machen...
Meiner Meinung nach ist für Java-Reflection keine VM oder auch JIT notwendig.Diese Meinung kann ich nicht nachvollziehen. In Java kriegst du die selben Probleme in Grün. Du hast halt keinen globalen Operator aber dafür ne statische Funktion.
-
Optimizer schrieb:
mathik schrieb:
Optimizer schrieb:
Wo muss man hier den bestehenden statischen Code ändern? Hier werden überall nur Zeiger bzw. Referenzen verwendet!
Ja, was ist hier? Dein Code jetzt? Super!
Und was ist mit meinem, legalen, standardkonformen C++ Code?Dein Code sieht schön und einfach aus. Ich kann nachvollziehen, dass man dafür einen JIT braucht.
Allerdings ist dort die ganze Typprüfung futsch! Nicht mal in Java funktioniet das so einfach, und unsicher! Dort musst du dir alles schön selber über die Class besorgen! (siehe Beitrag oben)
Klar. Das dynamische hinzuladen von Klassen hat Nachteile und Einschränkungen, das stand ja nie in Frage.
was du dort gepostet hast, mit dem << operator. sowas ist mit java reflection auch nicht möglich!
Doch. Ich kann auch statische Funktionen (wie der operator<< eine wäre) mit Reflection getten und aufrufen.
globale Funktionen gibt es bei Java nicht.
Man, jetzt bitte.
"(wie der operator<< eine wäre)". Nimm halt dann C#. Da kannst Operatoren schreiben. Der muss nicht außerhalb einer Klasse stehen. Er ist nicht Member und wird nicht dynamisch gebunden, das ist der Punkt. Und nicht, ob's global oder statisch ist. Sowas langweilt doch.BTW: es geht mir nicht darum, dass wir uns hier jetzt für C++ eine Reflection-API ausdenken. Mag seien, dass man für C++-reflection einen JIT benötigen würde. Will mir da auch echt kein Kopf drüber machen...
Meiner Meinung nach ist für Java-Reflection keine VM oder auch JIT notwendig.Diese Meinung kann ich nicht nachvollziehen. In Java kriegst du die selben Probleme in Grün. Du hast halt keinen globalen Operator aber dafür ne statische Funktion.
hierfür braucht man kein JIT:
Methode* statischeOp = dynamischeKlasse->getStaticMethod("operator<<", Class::forName("ostream"), Class::forName("DynamischeKlasse")) statischeOp->invoke(cout, dynamischeKlasse);
selbst in java musst du das so ähnlich machen!!
hierfür braucht man JIT:
cout<<dynamischeKlasse
das ist dann aber auch echt wie eine Skriptsprache...
sowas funktioniert nicht mal bei Java! dort musst du dir die statische Methode ersmal holen (siehe oben)
-
@optimizer
vielleicht könntest du ein Reflection-Beispiel in Java bringen, wo man einen JIT bräuchte.
-
Du brauchst allein schon nur nen Compiler, um sicherzustellen, dass der hinzugeladene Code im hineinzuladenden Kontext gültig ist.
class FooBlubberBar extends BlubberBar { @Override void foo() {...} }
Das ist eine perfekt gültige Klassendefinition.
Wenn du es aber in diesen Kontext hineinlädst:
[java]
final class BlubberBar extends java.lang.Object
{
void bar() {...}
}
[/java]
Dann passieren böse Dinge. Das @Override ist illegal und ableiten von BlubberBar auch. Mit ein paar trivialen Checks ist es IMHO nicht getan. Ehrlich gesagt möchte ich mir jetzt nicht noch weitere Beispiele ausdenken, aber ich zweifle nicht daran, dass es noch komplizierter geht. Die einzige saubere Lösung ist und bliebt compilieren.Dann hätten wir noch den bekannten Fall, dass vorhandener Code geändert werden muss:
MyType x = new MyType(); x.statischeMethode();
Wenn MyType eine statische Methode Namens statischeMethode() definiert, wird diese aufgerufen. Wenn es das nicht tut, muss eine statische Methode der Basisklasse mit dem Namen statischeMethode() aufgerufen werden. In Java ist nämlich der Aufruf einer statischen Methode über den statischen Typ einer Instanz erlaubt. Das ist vergleichbar mit dem Operator-Gefrickel in C++.
EDIT: Dazu passt natürlich, was bei der Dokumentation zu Class<T> steht, welche ja die ganzen Reflection-Informationen enthält.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html schrieb:
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
-
Optimizer schrieb:
Du brauchst allein schon nur nen Compiler, um sicherzustellen, dass der hinzugeladene Code im hineinzuladenden Kontext gültig ist.
class FooBlubberBar extends BlubberBar { @Override void foo() {...} }
Das ist eine perfekt gültige Klassendefinition.
Wenn du es aber in diesen Kontext hineinlädst:
[java]
final class BlubberBar extends java.lang.Object
{
void bar() {...}
}
[/java]
Dann passieren böse Dinge. Das @Override ist illegal und ableiten von BlubberBar auch. Mit ein paar trivialen Checks ist es IMHO nicht getan. Ehrlich gesagt möchte ich mir jetzt nicht noch weitere Beispiele ausdenken, aber ich zweifle nicht daran, dass es noch komplizierter geht. Die einzige saubere Lösung ist und bliebt compilieren.ich denke schon, dass die Checks vom ClassLoader durchgeführt werden können. Von mir aus, soll der ClassLoader einen ganzen Compiler haben, um die Checks durchzuführen. Vorhandener Code muss hierfür nicht geändert werden.
Optimizer schrieb:
Dann hätten wir noch den bekannten Fall, dass vorhandener Code geändert werden muss:
MyType x = new MyType(); x.statischeMethode();
Wenn MyType eine statische Methode Namens statischeMethode() definiert, wird diese aufgerufen. Wenn es das nicht tut, muss eine statische Methode der Basisklasse mit dem Namen statischeMethode() aufgerufen werden. In Java ist nämlich der Aufruf einer statischen Methode über den statischen Typ einer Instanz erlaubt. Das ist vergleichbar mit dem Operator-Gefrickel in C++.
hmmh...
man könnte auch statische Methoden in die vtable oder ähnliches packen.
Ich denke sogar, dass das auch bei java so gemacht wird...Optimizer schrieb:
EDIT: Dazu passt natürlich, was bei der Dokumentation zu Class<T> steht, welche ja die ganzen Reflection-Informationen enthält.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html schrieb:
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
Die Class-Objekte können auch dynamisch vom ClassLoader kontruiert werden (Class Class::forName(String)).
BTW: kennt jemand vielleicht ein Dokument von Sun oder Microsoft, wo steht, warum die sich für eine VM entschieden haben?
-
ich denke schon, dass die Checks vom ClassLoader durchgeführt werden können. Von mir aus, soll der ClassLoader einen ganzen Compiler haben, um die Checks durchzuführen. Vorhandener Code muss hierfür nicht geändert werden.
Ich habe auch nicht gesagt, dass hierfür Code geändert werden muss.
man könnte auch statische Methoden in die vtable oder ähnliches packen.
Ich denke sogar, dass das auch bei java so gemacht wird...So ein Unsinn. Statische Methoden stehen nicht in einer VTable und das wird auch nicht bei Java so gemacht. Aus welchen Grund sollte man das tun? Nur damit du angeblich auf einen JIT-Compiler verzichten kannst? Was für ein Quatsch.
Ich hab auch extra unterstrichen, dass der Methodenaufruf anhand des statischen Typs erfolgt, also nix dynamische Bindung. Es wäre ein Fehler, die statische Methode dynamisch zu binden (Fehler == es entspricht nicht der Spezifikation).Wie auch immer, ich klink mich jetzt aus.
-
Sovok schrieb:
n gewisser zeitaufwand wenn du updates für 20 plattformen erstellen musst
*rofl*?
wer stellt denn seine programme bitte für 20 programme bereit? 99% der programme laufen auf 32-bit windows und damit basta.anscheinend leiden vm-leute unter größenwahn: sie denken, dass sie plötzlich für alle systeme porten zu müssen, weil sie es vorher nicht schafften standard-nah zu
hacken und neuerdings denken sie auch noch, dass sie wie phönix aus der asche steigen und von den "profis" akzeptiert werden, so wie bill gates mit windows. AHAHAHAHA!mfg
-
btw: es heißt hier anscheinend öfters, dass plugins über vererbung zu stande kommen müssen. wozu? macht es doch wie in half-life (iirc):
eine struct mit functionspointer, die von den plugins (= mods) aufgerufen wird. die engine hat es dann schon gerichtet, und anscheinend funktioniert das prima, da cs und konsorten ansonsten wahrscheinlich im beta-stadium stecken geblieben wären...mfg