ich wollte mal Nachfragen, welche Nachteile oder besser Fehler ihr in
Java in Vergleich zu anderen Programmiersprachen seht. Ich meine nicht
Sachen die in Java und der Philosophie begründent liegen,
sondern Eigenschaften, die es unmöglich machen etwas bestimmtes zu
programmieren.
C++ Programmierer mögen Operatorüberladung und Mehrfachvererbeung
vermissen. Das meine ich z.B.
nicht. Denn beide Dinge kann man mehr oder weniger hübsch mit anderen
Konstrukten lösen.
Auch das Java als Programmierparadigma Objektorientierung (scheinbar)
erzwingt ist keine Einschränkung in dem Sinne.
Was ich meine sind harte Einschränkungen die es unmöglich machen etwas
bestimmtes zu programmieren oder wirklich zu schlimmeren Fehlern
führen.
Meine Beispiele:
1. Zerstörung von Objekten nicht "just in time".
--------------------------------------------------------------------
Garbagecollection und die Nichtnotwenigkeit sich um Aufräumarbeiten zu
kümmern mag ein Vorteil sein. Aber die Java-Garbagecollection
garantiert eben nicht - wie bei Python beispielsweise - die sofortige
Zerstörung (bzw. wenigstens den sofotigen Aufruf eines Destruktors)
wenn das Objekt den Sichtbarkeitsbereich verlässt.
D.h. durch verspätete destruierung bzw. der Unmöglichkeit einer
automatischen Destruierung entstehen Ressourcenleaks! Entgegen dem
Java-Versprechen...
2. Kein impliziter Copycontructor.
------------------------------------------------
Aus Bibliothek gibt es eine Klasse: (aufs wesentliche gekürzt)
class A{
private int a;
int getA(){return a;}
}
Also unspannend. Ein simpler Datencontainer.
Jetzt benöge ich dazu eine Erweiterung, weil ich zusätzlich Daten
brauche:
class B extends A{
private int b;
int getB(){return b;}
void setB(int b){ this.b = b;}
}
Sieht auch unspektakulär aus.
Die Probleme beginnen wenn ich nur ein A Object bekomme aber ein B
Objekt für eigene Zwecke brauche:
Z.B.
// get A from the library function, that can only return an A
A a = libClass.createA();
// now I need the B...
B b = new B(a); //geht nicht!!!!!!!*
myClass.machwasmitB(b);
*ja, ja, syntaktisch geht das schon, ich kann einen solchen
Konstruktor schreiben.
B(A a){}
Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
Object _ist_ wird niemals
die private Variable a übernehmen.
3. Aufruf einer Funktion einer höheren Basisklasse nicht möglich
---------------------------------------------------------------------------------------------
Kein super.super.function(); möglich. Das ist Mist.
class A(){
void function1(){ /* ....*/};
void function2(){ /* ....*/};
}
class B extends A(){
void function2(){
/* ...was B-spezifisches... */
super.function2(); //die benötigte A funktionalität
};
void function3(){/*....*/}
}
class C extends B(){
void function2(){
/* ...was C-spezifisches... */
//super.function2(); //nein!!!!, ich will nix B-spezifisches!!!!
super.super.function2(); //aber das geht nicht
}
};
Fällt euch noch mehr ein?
Eine solche Diskussion ist in der Regel relativ sinnlos, weil sich alles
irgendwie simulieren lässt. Kommt nur auf den Aufwand an.
[...]
> Meine Beispiele:
>
> 1. Zerstörung von Objekten nicht "just in time".
um dich zu zitieren: "Sachen die in Java und der Philosophie begründent
liegen". Warum gilt das für das "zerstören" von Objekten plötzlich nicht?
> --------------------------------------------------------------------
> Garbagecollection und die Nichtnotwenigkeit sich um Aufräumarbeiten zu
> kümmern mag ein Vorteil sein. Aber die Java-Garbagecollection
> garantiert eben nicht - wie bei Python beispielsweise - die sofortige
> Zerstörung (bzw. wenigstens den sofotigen Aufruf eines Destruktors)
> wenn das Objekt den Sichtbarkeitsbereich verlässt.
> D.h. durch verspätete destruierung bzw. der Unmöglichkeit einer
> automatischen Destruierung entstehen Ressourcenleaks! Entgegen dem
> Java-Versprechen...
Ressourcen kann man auch schliessen ohne einen Destruktor zu benutzen.
Das Problem ist ja nicht so sehr das explizite Zerstören, sondern dass
das auch gemacht werden muss, wenn niemand den Destruktor im Code
aufruft. Übrigens werden in Java Objekte meist auch sofort collected,
wenn du sie in einer Methode angelegt hast und nach verlassen der
Methoden nicht mehr referenzierst. Das Problem sind doch eher langlebige
Objekte. Garantiert denn C++ dass der Destruktor aller Objekte
aufgerufen wird, wenn die Anwendung abstürzt?
Ich finde überhaupt mit finalize angefangen zu haben war ein Fehler.
Aber man wollte wohl die C++-Leute nicht so extrem vergraulen.. wegen
denen hat man ja auch primitives eingeführt. Ja gut, ich will es nicht
auf C++ schieben, das waren sicher noch genug andere ;)
> 2. Kein impliziter Copycontructor.
wie das zu Fehlern führt bin ich ja mal gespannt.
[...]
> // get A from the library function, that can only return an A
> A a = libClass.createA();
>
> // now I need the B...
> B b = new B(a); //geht nicht!!!!!!!*
> myClass.machwasmitB(b);
>
> *ja, ja, syntaktisch geht das schon, ich kann einen solchen
> Konstruktor schreiben.
Zitat: "die es unmöglich machen etwas bestimmtes zu programmieren."
also meinst du ja was anderes ;)
> B(A a){}
>
> Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
> Object _ist_ wird niemals
> die private Variable a übernehmen.
ja und? Warum muss ich auch ein B konfigurieren mittels eines A? Und
vielleicht hast du ja mal die Diskussionen zu clone() verfolgt, das
stösst doch in die exakt gleiche Richtung, oder nicht? Ausserdem wer
sagt denn das in a ein A gespeichert ist und nicht eine Subklasse davon.
Wenn dem aber so ist, dann verliere ich ja informationen, zum Beispiel
überschriebene Methoden. Ich würde eher eine Art Adapter oder Proxy
verwenden. Wenn überhaupt einen Copy constructor, dann ja wohl mit B(B),
nicht mit A. Und dann würde ich persönlich noch eine Exception
schmeissen wenn this.getClass() != b.getClass().
In C++ macht das in Kombination mit der Zuweisung vielleicht mehr Sinn,
aber in einer Sprache in der ich nicht zwischen Pointer auf einen Wert
und den Wert direkt wählen kann?
Und zu guter letzt... mit Reflection kann ich auch den Wert für a kopieren.
> 3. Aufruf einer Funktion einer höheren Basisklasse nicht möglich
> ---------------------------------------------------------------------------------------------
>
> Kein super.super.function(); möglich. Das ist Mist.
>
> class A(){
> void function1(){ /* ....*/};
> void function2(){ /* ....*/};
> }
>
> class B extends A(){
> void function2(){
> /* ...was B-spezifisches... */
> super.function2(); //die benötigte A funktionalität
> };
> void function3(){/*....*/}
> }
>
> class C extends B(){
> void function2(){
> /* ...was C-spezifisches... */
> //super.function2(); //nein!!!!, ich will nix B-spezifisches!!!!
> super.super.function2(); //aber das geht nicht
> }
> };
es mag ja sein, dass dies nicht geht, aber in welchen Fällen braucht man
das überhaupt? Normalerweise kann man durch eine Änderung des Design dem
entgegen wirken. Den normalerweise hatte man dann Klassen die schlecht
strukturiert sind. Oder hast du einen konkreten, realistischen Fall wo
man sowas wirklich braucht?
Gruss theo
--
Jochen "blackdrag" Theodorou
Groovy Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
Wenn Du Sachen meinst, die an Java nicht "gefallen" .. davon gibt es
bestimmt vieles .. wie bei jeder anderen Sprache auch.
(z.B. Plattformunabhängig aber ggf. VM- bzw. VM-Versionsabhängig,
wesewegen man häufig diverse VMs installiert haben muss etc.pp.)
Es gibt keine Moeglichkeit zu testen, ob der Typ eines Objekts eine
Unterklasse einer gegebenen anderen Klasse ist. Das hat zur Folge, dass
eine Unterklasse die Methode equals() ihrer instaniierbaren Superklasse
"zerstoert". Hier ist ein Beispiel:
// Superklasse
public class A {
private String s;
public A(String s) {
this.s = s;
}
public String getS() { return s; }
@Override
public boolean equals(Object obj) {
if (! (obj instanceof A)) // true for subclasses
return false;
A other = (A) obj;
return s.equals(other.s);
}
@Override
public int hashCode() {
return s.length();
}
}
// Subklasse
public class B extends A {
private String c;
private int x;
public B(String s, String c, int x) {
super(s);
this.c = c;
this.x = x;
}
@Override
public boolean equals(Object obj) {
if (! (obj instanceof B))
return false;
B other = (B) obj;
return super.equals(other) && c.equals(other.c) && x == other.x;
}
@Override
public int hashCode() {
return super.hashCode() + 3 * c.length() + 7 * x;
}
}
// Test
import java.util.*;
public class Test {
public static void main(String[] args) {
A a = new A("abc");
B b = new B("abc", "abcabca", -3);
Set<A> set = new HashSet<A>();
set.add(a);
set.add(b);
System.out.println("Size of the set: " + set.size());
set.clear();
set.add(b);
set.add(a);
System.out.println("Size of the set: " + set.size());
}
}
Die Ausgabe des Tests:
Size of the set: 2
Size of the set: 1
Dieses Verhalten ergibt sich dadurch, dass HashSet vor dem Einfuegen
prueft, ob es das neu einzufuegende Objekt schon enthaelt. Die Klasse
vergleicht dazu die HashCodes, und ruft equals() genau dann auf, wenn
die HashCodes gleich sind. Die Parameter der Konstruktoren A() und B()
ergeben "zufaellig" :-) die gleichen HashCodes, also wird equals()
aufgerufen. Das Problem ist nun, dass A#equals() den Wert true
zurueckgibt, B#equals() dagegen false.
Die Moral von der Geschichte kann nur sein, dass man keine verschiedenen
instantiierbaren Typen der gleichen Vererbungshierarchie in dieselbe
Collection stecken darf. Der Grund ist die Assymetrie den Operators
"instanceof", bzw. das Fehlen eines Gegenstuecks, das in die andere
Richtung assymetrisch ist.
op
wie wäre:
> // Superklasse
> public class A {
[...]
> @Override
> public boolean equals(Object obj) {
> if (getClass()!=A.class || obj.getClass()!=A.class)
> return false;
> A other = (A) obj;
> return s.equals(other.s);
> }
[...]
in dem Fall würde equals nur true ergeben, wenn obj ein A ist (und keine
Unterklasse) und this ein A ist (und keine Unterklasse). Natürlich macht
dann der Aufruf super.equals(other) in B absolut 0 Sinn mehr. Jedenfalls
gibt es da Class#isAssignable, das ich benutzen kann um das Verhältnis
zweier Klassen zu prüfen. Und in dem Fall auch symetrisch. Deine Aussage
"Es gibt keine Moeglichkeit zu testen, ob der Typ eines Objekts eine
Unterklasse einer gegebenen anderen Klasse ist" ist also so nicht richtig.
Nein tun sie nicht. Und es gibt ein workaround: dispose() methoden für
expliziten destruktor.
> Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
> Object _ist_ wird niemals
> die private Variable a übernehmen.
Aber es gibt ja genug Workarounds: das Object kann sich selber kopieren oder
du benutzt serialisierung. Gemaess deiner Definition ist das keine
"ernsthafte" restriktion.
> Kein super.super.function(); möglich. Das ist Mist.
Ich glaube ich will deine Designs und den quellcode nicht sehen :)
Gruss
Bernd
Du meinst man kann nicht prüfen ob es keine unterklasse ist? das geht mit
a.getClass()==b.getClass()
Gruss
Bernd
Wieso nicht? Vorrausgesetzt A hat natürlich einen Konstruktor der das
int a übergeben bekommt. Aber sonst bekommst du ja in A nie nen Wert rein.
public B(int a,int b)
{
super(a);
this.b = b;
}
public B(A a,int b)
{
this(a.getA(),b);
}
>
> 3. Aufruf einer Funktion einer höheren Basisklasse nicht möglich
> ---------------------------------------------------------------------------------------------
>
> Kein super.super.function(); möglich. Das ist Mist.
Findest du, ich hab das noch nie gebraucht.
>
> class A(){
> void function1(){ /* ....*/};
> void function2(){ /* ....*/};
> }
>
> class B extends A(){
> void function2(){
> /* ...was B-spezifisches... */
> super.function2(); //die benötigte A funktionalität
> };
> void function3(){/*....*/}
> }
>
> class C extends B(){
> void function2(){
> /* ...was C-spezifisches... */
> //super.function2(); //nein!!!!, ich will nix B-spezifisches!!!!
> super.super.function2(); //aber das geht nicht
> }
> };
>
>
> Fällt euch noch mehr ein?
>
Du kannst kein Swap schreiben so wie du es von anderen Sprachen gewohnt
bist, da es kein Call by Referenz gibt.
Generics sind nicht so mächtig wie Templates in C++.
Da gibt es sicherlich ein paar Sachen. Aber programmieren kannst du
alles, Java ist ja Turingvollständig ;). Außerdem die schlimmeren Fehler
kannst du sicherlich in C++ bauen (Bufferoverflow, Memory Leaks, ...).
Was für mich eine gute Sprache ausmacht ist aber nicht der Sprachumfang
sondern die API und zusätzliche Frameworks für die Sprache. Da finde ich
Java traumhaft.
mfg
Andreas
Der Memory Overhead um Primitive (in Collections) und Strings zu
bearbeiten ist
aber beträchtlich. Einige Sachen wären durchaus innerhalb von 2GB und
mit der 32bit JVM zu machen, wenn nicht Java so viel drauflegen würde.
Hier ein etwas älterer Artikel von SMA, der dies zeigt (und auch eine
Lösung für Strings)
Gruß
Wolfgang R.
In diesem Artkel steht einiges zum Speicherlayout von Objekten:
ftp://www6.software.ibm.com/software/developer/jdk/diagnosis/GCandMemory-042005.pdf
Leider nichts über Primitive.
Zum Thema zwar etwas unpassend, aber ich wills einfach mal sagen:
So manches Gross-Projekt wäre ohne Java sehr viel schwerer
oder unmöglich.
Das fängt schon mit dem Kompilieren an.
Keine Header-Dateien und keine einzuhaltende Reihenfolge
der Deklaration und Benutzung aller Entitäten.
Rekursive Deklaration von Klassen kein Problem.
javac und ant usw machen den ganzen make-Kram mit.
Linken nicht notwendig.
Laufzeit:
Alles viel sicherer und die JVM lädt nur die Klassen,
die sie benötigt. Alles andere bleibt draussen,
egal wieviel Code das ganze Projekt hat.
Bei C/C++ müsste man da schon mit DLLs oder
*.so oder *.bin arbeiten.
Ich glaube, die binden sich auch nicht so natürlich wie
Interface-Implementierungen in die Sprache ein.
Komponenten:
OSGi oder die neuen Super-Packages
So was gibt es unter C/C++ gar nicht.
Entwickeln:
Bequem auf Eclipse oder anderer IDE unter
Windows entwickeln und später läuft es auf
Host (zOS) oder Linux oder Solaris.
Alles sehr einfach und bequem.
Heiner
www.heinerkuecker.de
Ich selbst habe auch wenig an Java auszusetzen und versuche
möglichst alles in Java zu lösen. Hab einfach keine Lust im
Augenblick eine weitere Sprache zu lernen.
Ok, einige kleine Sachen sind in einer Unix Shell auch sehr
zeitsparend zu lösen.
Den Punkt den ich oben erwähnt habe betrifft einen kleinen
Sprachenstreit mit meinen Kollegen aus der SQL Fraktion.
Wir haben eine große Oracle Datenbank und müssen (off-line)
Daten extrahieren und ein temporäres Modell bauen. Die
Kollegen verstricken sich in immer komplexere SQL Statements
und die Laufzeit der Queries ist auch beträchtlich.
Meine Idee ist den erforderliche Subset in Java Objekte in
Memory zu laden und dann die Verknüpfungen auf den
Maps zu programmieren. Sollte doch extrem schnell sein,
wenn ich nicht mehr die Platte kontaktieren muß. Bin mir
aber nicht sicher, wie optimal dies auch schon von SQL/Oracle
auf der anderen Seite gemacht wird.
Wenn ich aber schon für einen String mit einem Character
50 byte belege, brauche ich bei unserer Datenmenge erst
gar nicht anfangen. Allein wenn ich in Java mit 1 byte chars
arbeiten könnte, wäre das schon super.
Gibt es irgendwo eine Bibliothek, um nicht zu kompliziertes
String Handling mit 1 byte ASCII Strings zu machen?
Gruß
Wolfgang R.
> Ressourcen kann man auch schliessen ohne einen Destruktor zu benutzen.
> Das Problem ist ja nicht so sehr das explizite Zerstören, sondern dass
> das auch gemacht werden muss, wenn niemand den Destruktor im Code
> aufruft.
Aufrufen _kann_.
> Übrigens werden in Java Objekte meist auch sofort collected,
> wenn du sie in einer Methode angelegt hast und nach verlassen der
> Methoden nicht mehr referenzierst.
Meist...
> Garantiert denn C++ dass der Destruktor aller Objekte
> aufgerufen wird, wenn die Anwendung abstürzt?
Bei ordentlichem Design: ja.
Aber das erfordert wirklich ordentliches Design insbsondere bei
Exeptionhandling.
> Ich finde überhaupt mit finalize angefangen zu haben war ein Fehler.
> Aber man wollte wohl die C++-Leute nicht so extrem vergraulen.. wegen
> denen hat man ja auch primitives eingeführt.
Stimme ich dir zu. Java hätte weniger Rücksicht auf C++ nehmen sollen.
Die Ähnlichkeit ist in keine Weise gut.
> Zitat: "die es unmöglich machen etwas bestimmtes zu programmieren."
> also meinst du ja was anderes ;)
Nä. Ich will ganz einfach eine Funktion aus der Ur-Basis aufrufen.
Das geht nur solange sie in der Basis nicht redifiniert wird.
Ein expliziter Aufruf via Scope-Operator ist nicht möglich.
> Ausserdem wer
> sagt denn das in a ein A gespeichert ist und nicht eine Subklasse davon.
Der Debugger.
> Ich würde eher eine Art Adapter oder Proxy
> verwenden.
Ähnliche Antworten ala "das Design ist schlecht" kamen auch von anderen
hier. Leider übersehen diese das Entscheidende: das Design stammt nicht
von mir. Ich muss es benutzen! Aus Fremdbibliotheken! Aus anderen
projekten die historisch so gewachsen sind.
Das ideale Design ist graue Theorie. In der Theorie habt ihr recht.
> Und zu guter letzt... mit Reflection kann ich auch den Wert für a kopieren.
Nein, kann ich nicht (immer).
Wann genau nicht müsste ich dir raussuchen. Weiss ich nicht mehr.
> es mag ja sein, dass dies nicht geht, aber in welchen Fällen braucht man
> das überhaupt? Normalerweise kann man durch eine Änderung des Design dem
> entgegen wirken. Den normalerweise hatte man dann Klassen die schlecht
> strukturiert sind. Oder hast du einen konkreten, realistischen Fall wo
> man sowas wirklich braucht?
Der konkrete Fall, war eine (nicht von mir) so "schlecht strukturierte"
Klasse. Aber ich hätte es höchstwahrscheinlich selber so gemacht, denn
das was ich machen wollte war so nie vorgesehen. Ein Redesign kam schon
aus Zeitgründen nicht in Frage.
Entweder der Aufrufer ruft den Destruktor auf wenn er so weit ist (und das
geht auch in Java, siehe dispose() und close()) oder man überlässt es dem GC
es irgendwann zu tun. Welchen anderen Ansatz vermisst du und welche Sprache
hat diesen?
(und ich hab schon Funktionale Interpreter mit einem konventionellen GC
gesehen)
> Die Ähnlichkeit ist in keine Weise gut.
Ja, die Generics sind haesslich und unnötig.
Gruss
Bernd
> In Java muss man wissen was man tut. Ressourcen schließt man selbst. Vom
> Aufwand kommt das doch auf das selbe raus, ob ich nun eine Methode
> aufrufe die die Resource schließt oder den Destruktor ist doch egal.
> Wenn es Python automatisch so macht ist es sicher schön, aber selbst
> wenn es in Java nicht so ist, eine Einschränkung sehe ich da nicht.
Du hattest noch nie Ressourcen leaks? (Datenbank connections z.B.)
>> Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
>> Object _ist_ wird niemals
>> die private Variable a übernehmen.
> Wieso nicht? Vorrausgesetzt A hat natürlich einen Konstruktor der das
> int a übergeben bekommt.
Hat A selbstverständlich nicht, sonst wäre das Problem ja trivial.
> Aber sonst bekommst du ja in A nie nen Wert rein.
Man kann Werte in Klasseninstanzen durchaus auch anders setzen als
per Kontruktor und Setter-Funktionen.
Die Welt besteht nicht nur aus Bohnen...
>> Kein super.super.function(); möglich. Das ist Mist.
> Findest du, ich hab das noch nie gebraucht.
Ich schon.
> Du kannst kein Swap schreiben so wie du es von anderen Sprachen gewohnt
> bist, da es kein Call by Referenz gibt.
Naja. Mit Containern kannst du das basteln.
Abgesehen davon: in Python geht das am allerbesten.
a, b = b, a;
> Generics sind nicht so mächtig wie Templates in C++.
Generics in Java suboptimal um es mal euphemistisch zu sagen.
Der Beginn von Ende der Sprache.
> Was für mich eine gute Sprache ausmacht ist aber nicht der Sprachumfang
> sondern die API und zusätzliche Frameworks für die Sprache. Da finde ich
> Java traumhaft.
Na gut, totgesagte leben länger...
In der Tat ist Java schon damit ein Selbstläufer.
Java ist ja nicht schlecht. Nur leider zu sehr gegenüber C++ gelobt und
C++ verteufelt. Ich erlebe das in Diskussionen auf Arbeit sehr häufig.
>> Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
>> Object _ist_ wird niemals
>> die private Variable a übernehmen.
> Aber es gibt ja genug Workarounds: das Object kann sich selber kopieren
Hä? Dann habe ich wieder ein A. Ich will aber ein B.
> du benutzt serialisierung.
Erklär mal bitte. Da stehe ich grad auf dem Schlauch.
> Ich glaube ich will deine Designs und den quellcode nicht sehen :)
Lass es mich so ausdrücken: Die Designs und den Quellcode der solche
Fragen aufwirft, den willst du wirklich nicht sehen...;-)
> Im mathematischen Sinne ist Java vollständig, also kannst Du jedes
> berechenbare Problem damit lösen.
Das ist eine andere Frage.
Die Frage ist kann schon gelöste Probleme (anderen Code) so anwenden,
wie ich es brauche?
> Wenn Du Sachen meinst, die an Java nicht "gefallen" .. davon gibt es
> bestimmt vieles ..
Dann erzähl mal. Lass uns ein bisschen Java-Bashing betreiben...;-)
> Welchen anderen Ansatz vermisst du und welche Sprache
> hat diesen?
Sofortige Zerstörung des Objects bei Verlassen des Scopes.
-> Python
Bei Exceptions müssen Ressourcen explizit freigegeben werden.
Was gerne passiert ist z.B. dass Connections aus einem
Connection-Pool nicht schnell genug freigegeben werden.
Ich trau mir zumindest keine solchen grossen C++ Projekte zu die ich in Java
manage. Dann doch eher .Net.
Gruss
Bernd
> Ich trau mir zumindest keine solchen grossen C++ Projekte zu die ich in Java
> manage.
Also ich schon.
Da wir in der Firma aber hauptsächlich Java programmieren sind die
großen Projekte halt Java.
Nur ist der große Vorteil von Java, leichter erlernbar zu sein,
gleichzeitig der größte Nachteil: Es programmieren auch zu viele
schlechte Leute mit, die bei C++ "Segmentation fault"
schon aussortiert hätte.
In einem wirklich gut gemanagten und designten Projekt ist die
Frage der Sprache eh zweitrangig.
hast du denn erfahrungen mit grossen projekten?
> In einem wirklich gut gemanagten und designten Projekt ist die
> Frage der Sprache eh zweitrangig.
kennst du welche?
Gruss
Bernd
mischt du da nicht 2 Dinge? Im Connection-Pool hast du keine Methode die
du verlassen würdest um den GC automatisch anzuweisen die Objekte
aufzuräumen. Mach doch nicht aus langlebigen und kurzlebigen Objekte
einfach eins. Denn wenn wir nur Objekte aufräumen müssten, wenn eine
Methode verlassen wird, dann bräuchte man gar keinen GC wie er bei Java
zur Anwendung kommt.
ja weiter?
>> Übrigens werden in Java Objekte meist auch sofort collected, wenn du
>> sie in einer Methode angelegt hast und nach verlassen der Methoden
>> nicht mehr referenzierst.
>
> Meist...
kommt auf den GC an eben.
>> Garantiert denn C++ dass der Destruktor aller Objekte aufgerufen wird,
>> wenn die Anwendung abstürzt?
>
> Bei ordentlichem Design: ja.
> Aber das erfordert wirklich ordentliches Design insbsondere bei
> Exeptionhandling.
kommt ja scheinbar selten vor. Ausserdem klingt das danach dass ich es
ja dann eh wieder von Hand machen muss, womit sich für mich der
Unterschied zu Java nicht erschliesst.
[...]
>> Ausserdem wer sagt denn das in a ein A gespeichert ist und nicht eine
>> Subklasse davon.
>
> Der Debugger.
der war gut ;) Fröhliches schreiben von Bibliothken wünsche ich dann.
>> Ich würde eher eine Art Adapter oder Proxy verwenden.
>
> Ähnliche Antworten ala "das Design ist schlecht" kamen auch von anderen
> hier. Leider übersehen diese das Entscheidende: das Design stammt nicht
> von mir. Ich muss es benutzen! Aus Fremdbibliotheken! Aus anderen
> projekten die historisch so gewachsen sind.
> Das ideale Design ist graue Theorie. In der Theorie habt ihr recht.
Mag schon sein, aber in C++ bekommst du exact das gleiche Problem wenn
jemand das automatische Anlegen des Copy-Konstruktor verhindert hat und
mit dem Ersatz Schindluder treibt.
>> Und zu guter letzt... mit Reflection kann ich auch den Wert für a
>> kopieren.
>
> Nein, kann ich nicht (immer).
> Wann genau nicht müsste ich dir raussuchen. Weiss ich nicht mehr.
Schau nur ruhig nach, aber es geht, man muss nur den Zugriff auf private
explizit Freigeben, was ein Securitymanager verhindern kann. Ohne den
kann ich auch zum Beispiel Strings ändern. (man schreibt in das private
char[] Feld).
Mag ja sein dass in C++ ein paar mehr Dinge ganz automatisch gehen, für
die man in Java explizit etwas tun muss, andererseits gehört das auch
zur Philosohie von Java
da sage ich ganz klar: kommt darauf an ;)
Ich meine erwartest du wirklich das ein Lisp-Programm ohne grössere
Änderungen in Java funktioniert?
Es sind verschiedene Sprachen mit unterschiedlichen Konzepten. Oder wie
ist "wie ich es brauche" zu verstehen?
>> Wenn Du Sachen meinst, die an Java nicht "gefallen" .. davon gibt es
>> bestimmt vieles ..
>
> Dann erzähl mal. Lass uns ein bisschen Java-Bashing betreiben...;-)
du meinst so Sachen wie das man das Gefühl hat man wird wie eine Art
Kleinkind behandelt? oder das man ohne IDE kaum arbeiten kann? In einem
anderen Teil hast du dich darüber beschwert das so viele Java
programmieren, die keine Ahnung haben. Ist ja auch kein Wunder, das ist
schliesslich Teil der Philosophie...
> hast du denn erfahrungen mit grossen projekten?
Ja. Aber alle großen Projekte wo ich selber beteiligt war, waren in Java.
C++ waren meist eher kleinere Dinge.
>> In einem wirklich gut gemanagten und designten Projekt ist die
>> Frage der Sprache eh zweitrangig.
> kennst du welche?
gut gemanagten und designten Projekt? Nein.
> du meinst so Sachen wie das man das Gefühl hat man wird wie eine Art
> Kleinkind behandelt?
Ja. Genau.
> oder das man ohne IDE kaum arbeiten kann?
Stimmt nicht!
Ich hab schon ein J2EE-Projekt mit Ultra-Edit gemacht.
Allerdings nur change requests gemacht und bugfixing.
IDE-Schwein...und vielleicht auch noch Syntakhighlighting...Weichei ;-)
> anderen Teil hast du dich darüber beschwert das so viele Java
> programmieren, die keine Ahnung haben. Ist ja auch kein Wunder, das ist
> schliesslich Teil der Philosophie...
Was ich für ein Problem halte. Generell aber auf Management-Ebene.
Ich möchte niemanden einen Vorwurf machen, der als Quereinsteiger
subobtimal programmiert. War ich ja selber mal.
Aber wenn "oben" indirekt die Einstellung herrscht, dass man lieber
von C++ die Finger lässt, weil wir nur wenige C++ Programmierer sind.
Aber dass man jeden Depp an Java lässt, herrscht mir hier eine leichte
Schieflage vor. Was auch Java nicht gut tut.
Wie gesagt, schlecht ist die Sprache nicht. Sie ist mit einer der
besseren. Nur neben Python und C++ sehe ich nicht so viel Bedarf
für eine Sprache wie Java. Wenn dann schon eine ganz andere Sprache.
Mit völlig anderem Konzept. So ist es mehr ein kastriertes C++ mit VM.
wenn die Sprache was taugt brauch' ich das nicht ;) Zum Beispiel sind
mit Groovy die Programme in der Regel kürzer, womit man automatisch
weniger die IDE brauchen würde
>> anderen Teil hast du dich darüber beschwert das so viele Java
>> programmieren, die keine Ahnung haben. Ist ja auch kein Wunder, das
>> ist schliesslich Teil der Philosophie...
>
> Was ich für ein Problem halte. Generell aber auf Management-Ebene.
> Ich möchte niemanden einen Vorwurf machen, der als Quereinsteiger
> subobtimal programmiert. War ich ja selber mal.
> Aber wenn "oben" indirekt die Einstellung herrscht, dass man lieber
> von C++ die Finger lässt, weil wir nur wenige C++ Programmierer sind.
ist doch verständlich.
> Aber dass man jeden Depp an Java lässt, herrscht mir hier eine leichte
> Schieflage vor. Was auch Java nicht gut tut.
Das liegt meiner Meinung nach an der Verbreitung der Sprache und das
wiederum hängt mit der Erlernbarkeit und Wartbarkeit der Sprache
zusammen. Und da sehe ich nunmal Java überlegen.
> Wie gesagt, schlecht ist die Sprache nicht. Sie ist mit einer der
> besseren. Nur neben Python und C++ sehe ich nicht so viel Bedarf
> für eine Sprache wie Java. Wenn dann schon eine ganz andere Sprache.
> Mit völlig anderem Konzept. So ist es mehr ein kastriertes C++ mit VM.
Python tut sich schwer wegen seiner Formatierung. So blöd das klingt,
das ist ein Grund. Und C++ leistet nicht was Java leistet wenn es darum
geht unabhängig von der Plattform zu sein, einfach zu compilieren und zu
linken. Auch wenn man nur auf Windows arbeitet, so spielt die
Unabhägigkeit von der Plattform doch eine Rolle. Und für andere
Anwendungen dürfte die Schwierigkeit mittels eines Bufferoverflows einen
Schädling zu bekommen ein Grund gewesen sein. Von daher sehe ich in Java
kein kastriertes C++, es ist was eigenes, mit eigenem Ökosystem.
Nur Anfänger allokieren solche Ressourcen in einem Konstruktor - oder
Leute die auch sonst Türen zwar öffnen, aber nie wieder schliessen,
weil sie in der S-Bahn geboren sind. Ressourcen allokiert man so
kurz wie möglich und behandelt diese auch explizit, wofür es in den
Interfaces ja auch passende close()-Methoden gibt.
> ...
> Man kann Werte in Klasseninstanzen durchaus auch anders setzen als
> per Kontruktor und Setter-Funktionen.
Reflection?
> Die Welt besteht nicht nur aus Bohnen...
Stimmt - man kann auch Kakao trinken.
>>> Kein super.super.function(); möglich. Das ist Mist.
>>
>> Findest du, ich hab das noch nie gebraucht.
>
> Ich schon.
Dann ist dein Design einfach nur Murks - das braucht
kein Mensch.
> ...
> In der Tat ist Java schon damit ein Selbstläufer.
> Java ist ja nicht schlecht. Nur leider zu sehr gegenüber C++ gelobt und
> C++ verteufelt. Ich erlebe das in Diskussionen auf Arbeit sehr häufig.
Jede Sprache hat ihre Daseinsberechtigung. Man muss nur wissen,
was man will. Und ich möchte z.B. keine WebApp mit C++ schreiben.
Allerdings die Weiterentwicklung von Java macht daraus langsam
aber sicher eine bunte Mischung aus syntaktischen Schnipseln
aller Art - irgendwann wird's unerträglich.
Alfred
Genau und wenn's wirklich _gutes_ Design sein soll, dann
taucht ein "super.super.function();" gar nicht auf - Oder?
Alfred
Vielleicht reicht ja mein kleines Hirn nicht ganz aus,
aber seit wann soll ein _privates_ Member übernommen werden?
Ich sehe deine Einschränkungen bei Java jedenfalls nicht
so ganz und wüsste spontan auch nicht, was ich in der
täglichen Praxis mit Java gar nicht hinbekommen würde.
Und noch ein Zitat von dir:
> Java ist ja nicht schlecht. Nur leider zu sehr gegenüber C++
> gelobt und C++ verteufelt. Ich erlebe das in Diskussionen auf
> Arbeit sehr häufig.
Du trittst gerade genau auf diesem Pfad - nur andersrum...
Alfred
>>>> Kein super.super.function(); möglich. Das ist Mist.
> Dann ist dein Design einfach nur Murks - das braucht
> kein Mensch.
Sorry, aber das ist immer zu einfach!
Diese Aussage ist zu 90% ein Zirkelschluß derart, dass ein
Design mist sei, nur weil es _in dieser Sprache_ ungünstig ist.
Worauf ich eigentlich hinauswollte sind sprachunabhängige
Designpatterns die nur deswegen in Java "schlechtes Design"
sind, weil sie in Java nicht gehen.
Auch in anderen Sprachen fehlen mir manchmal Dinge.
In C++ fehlt mir z.B. das "final" was weiteres Überschreiben
einer Methode verbietet. Umgekehrt fehlt mir ein beiden allen
Sprachen ein Schlüsselwort ala "overwrite" was redefinition
einer Methode in einer abgeleiteten Klasse erzwingt.
public class A{
public void allgemeineMethode(){}
public void overwrite spezifischeMethode(){}
}
public class B extends A{
public void nochNeMethode(){}
}
->compile error: B must be declared abstract or redefine
spezifischeMethode()...
Ja, klar, geht auch mit Bordmittel. Aber es würde eine Klasse
sparen, was den üblichen Java-Klassen-Wald verringern würde.
> Allerdings die Weiterentwicklung von Java macht daraus langsam
> aber sicher eine bunte Mischung aus syntaktischen Schnipseln
> aller Art - irgendwann wird's unerträglich.
Voll zustimm. Ab Java 1.5 gehts abwärts.
Es beginnt das was auch C++ geschadet hat. Eine verkomplizierung der
Sprache die mehr Nachteile als Nutzen bringt.
In C++ sind das z.B. schlüsselwörter wie mutable, oder sogar die
templates. Kein Compiler den ich benutze (visual C++ und Gcc)
kann mit templates so umgehen wie es der Standard verlangt. Export.
Mit Java sehe ich ähnliches. Java hat eine Daseinsberechtigung.
Und zwar ist ein Eckpfeiler die relative Überschaubarkeit.
>> Man kann Werte in Klasseninstanzen durchaus auch anders setzen als
>> per Kontruktor und Setter-Funktionen.
> Reflection?
Nicht nur. a kann aus einer nativen Methode stammen.
Oder aus dem Aufruf einer anderen Klasse, die mir - da anderes Package -
nicht sichbar ist.
a kann Ergebnis einer Berechnung oder internen Zählung sein.
a kann beim parsen entstanden sein, z.B. xmlbeans oder axis.
etc. pp.
a ist ja nur ein Beispiel. Entscheident ist, dass ich die
privaten Member gar nicht kenne, ja gar nicht kennen soll!
Trotzdem müssten sie übernommen werden.
Ein impliziter Copy-Contructor würde da Wunder wirken...
>> Die Welt besteht nicht nur aus Bohnen...
> Stimmt - man kann auch Kakao trinken.
BTW. es gibt auch Kakaobohnen...;-)
> Python tut sich schwer wegen seiner Formatierung. So blöd das klingt,
> das ist ein Grund.
Einen den ich zwar sehr oft höre, aber nicht nachvollziehen kann.
Denn oft sind genau diejenigen die die Formatierungspflicht bei
Python bemänglen die, die auf exakte Einhaltung eines Styleguides
mit definierter Anzahl von Lehrzeichen als Einrückung und richtiger
Klassersetzung bestehen.
> Von daher sehe ich in Java
> kein kastriertes C++, es ist was eigenes, mit eigenem Ökosystem.
Vielleicht ist es wirklich ein psychologisches Problem. Und genau
die Ähnlichkeit mit c++ führt zu diesen Diskussionen.
das ist eine rein psychologische Sache. Es bedarf da keines logischen
Grundes... vielen gefällt das "Schriftbild" einfach nicht.
>> Von daher sehe ich in Java kein kastriertes C++, es ist was eigenes,
>> mit eigenem Ökosystem.
>
> Vielleicht ist es wirklich ein psychologisches Problem. Und genau
> die Ähnlichkeit mit c++ führt zu diesen Diskussionen.
Also ich sehe das nicht so eng... Da arbeitet man einmal mit Common
Lisp, das andere mal mit Scheme. Verschiedene Sprachen, aber extrem
ähnlich. Dann arbeitet man mit C oder C++... Zu sagen die würden sich
syntaktisch fundamental unterschieden wäre auch gewagt. Oder nimm von
mir aus die ganzen Pascal Dialekte.. die sehen alle irgendwie gleich
aus. Die Pascal- und die C-Art sind die bekanntesten, und eine Sprache,
die nicht in dieses Schema passt wird halt kritisch begutachtet... so
wie zum Beispiel Python. Ich wette, würde man Python geschweifte
Klammern für die Blöcke verschreiben würde die Akzeptanz immens steigen.
> Ja, die Generics sind haesslich und unnötig.
>
> Gruss
> Bernd
Wieso das?
Ja, aber super.super ist generell schlecht, es verstößt gegen die Kapselung.
Ich wuesste garnicht wozu ich das brauche.
> einer Methode verbietet. Umgekehrt fehlt mir ein beiden allen
> Sprachen ein Schlüsselwort ala "overwrite" was redefinition
> einer Methode in einer abgeleiteten Klasse erzwingt.
Das tut doch abstract?
Gruss
Bernd
>> einer Methode verbietet. Umgekehrt fehlt mir ein beiden allen
>> Sprachen ein Schlüsselwort ala "overwrite" was redefinition
>> einer Methode in einer abgeleiteten Klasse erzwingt.
>
> Das tut doch abstract?
Er meint das der Art, dass die Methode in der Superklasse
durchaus definiert ist, bei einer Ableitung aber ebenfalls
ueberschrieben werden muss. Wenn Du Dir sein Beispiel
ansiehst, wirst Du zwei unscheinbare geschweifte Klammer
hinter der Methode sehen ;-)
Gruesse, Lothar
--
Lothar Kimmeringer E-Mail: spam...@kimmeringer.de
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)
Always remember: The answer is forty-two, there can only be wrong
questions!
Da muss ich Jochen ebenfalls widersprechen. Strukturierung durch
Einrückung (wie übrigens auch bei Haskell oder Occam) gefällt mir
ausgesprochen gut. Ich wünschte nur, ich würde meinen gvim besser
beherrschen und könnte leichte Blöcke ein- und ausrücken. Schließende
Klammern oder "end"-Schlüsselworte sind syntaktischer Ballast und es tut
gut, ihn nicht zu haben. Das kann denke ich auch ein Lisp-Entwickler
bestätigen.
Hier ist die Summenbildung über eine Collection in Java:
int sum(Collection<Integer> collection) {
int sum = 0;
for (Integer i : collection) {
sum += i;
}
return sum;
}
Und in Python:
def sum(seq):
sum = 0
for i in seq: sum += i
return sum
4 statt 7 Zeilen. Man würde es wahrscheinlich eher als
def sum(seq):
return reduce(int.__add__, seq)
schreiben (also 2 Zeilen), doch das wäre unfair.
> Denn oft sind genau diejenigen die die Formatierungspflicht bei
> Python bemänglen die, die auf exakte Einhaltung eines Styleguides
> mit definierter Anzahl von Lehrzeichen als Einrückung und richtiger
> Klassersetzung bestehen.
Was ich im Übrigens auch für wichtig halte.
--
Stefan Matthias Aust
> Was ich meine sind harte Einschränkungen die es unmöglich machen etwas
> bestimmtes zu programmieren oder wirklich zu schlimmeren Fehlern
> führen. [...]
Ich empfinde deine drei Beispiel allesamt als unkritisch. Für die
Verwaltung von Ressourcen musst du (geschwätzig wie immer in Java) ein
Resource r = aquire();
try {
use(r);
} finally {
dispose(r);
}
benutzen. Hier würde ich Java stattdessen vorwerfen, das man derartige
Codeabschnitte nicht abstrahieren kann, also dass das fehlt, was als
Closures durch die Diskussionen geistert.
In C# gibt es das Schlüsselwort using, in Python heißt es with.
Ich meine, du schriebst, dass Python ebenfalls Ressources sofort
freigibt. Das ist glaube ich ein Artefakt, was (jedenfalls in den
älteren Versionen) dem mangelhaften GC mittels Referenzzählung
geschuldet ist. Python 3k soll doch damit aufhören, oder? Dann wäre dort
das selbe von dir wahrgenommene Problem wie bei Java vorhanden.
Ich bin ein Fan von explizitem Kopieren und würde lieber besser
verhindern können, dass man Objekte ändern kann. Dies funktioniert
leider nur umständlich durch das definieren weiterer Interfaces und das
muss man im Voraus planen.
Ein "super.super" habe ich noch nie gebraucht.
> Fällt euch noch mehr ein?
Mich stört beispielsweise bei Java, das es keine Closures gibt, dass ich
keine lokale Typinferenz habe (beides Features, die C# 3.0 inzwischen
bietet) und das die aktuellen VMs beim Hot Code Replacement versagen,
sobald man die Objektstruktur ändert.
--
Stefan Matthias Aust
Stimmt - ist mir im Nachhinein auch aufgefallen.
Aber es gibt ja auch Tee - und den hats nicht in Bohnen.
Alfred
> 1. Zerstörung von Objekten nicht "just in time".
> --------------------------------------------------------------------
> Garbagecollection und die Nichtnotwenigkeit sich um Aufräumarbeiten zu
> kümmern mag ein Vorteil sein. Aber die Java-Garbagecollection
> garantiert eben nicht - wie bei Python beispielsweise - die sofortige
> Zerstörung (bzw. wenigstens den sofotigen Aufruf eines Destruktors)
> wenn das Objekt den Sichtbarkeitsbereich verlässt.
Das nicht, frueher oder spaeter wird das ganze aber abgeraeumt, was
fuer mich aufs gleiche herauskommt. Dein Beispiel mit wachsendem
Ressourcenverbrauch wuerde Dir aber auch woanders passieren, evtl.
aber garniert mit einem Coredump, weil Du durch Aufruf des Destruktors
Ressourcen freigegegen hast, die von anderer Seite dann ploetzlich
versucht wird, verwendet zu werden.
> D.h. durch verspätete destruierung bzw. der Unmöglichkeit einer
> automatischen Destruierung entstehen Ressourcenleaks!
Nein. Wenn Du weiter bei der Behauptung bleibt, haette ich gerne
einen Proof of Concept in Form eines Testcases.
> Fällt euch noch mehr ein?
Mir persoenlich gehen ab und zu Friend-Deklarationen ab, also
die Moeglichkeit, Methoden oder Members fuer bestimmte Klassen
sichtbar zu machen, fuer den Rest aber nicht. Man kann sich
zwar mit Package Visiblity behelfen, manchmal ist mir das aber
schon zu viel Sichtbarkeit.
> Ja, die Generics sind haesslich und unnötig.
Hässlich vielleicht, aber mir haben mir das eine oder andere mal den
Arsch gerettet - besonders beim Debuggen/Refactorn von altem Code mit
komplexen Datenstrukturen: da klatscht man erstmal Generics dran, um
besser zu sehen, was wohin gehört (ggf. fällt dort dann schon der erste
Fehler auf) und dann baut man das so um, dass man es vorzeigen kann.
Und den einen oder anderen Flüchtigkeitsfehler haben sie mir auch schon
erspart.
Gruß,
-Wanja-
--
Ada Byron, die Lochkarten für Babbages "Difference Engine" vorbereitete,
gilt als die erste Programmiererin der Weltgeschichte. Sie hat auch das
Verhaltensmuster für alle nachfolgenden Programmierer vorgegeben: Sie
trank und schluckte Drogen.
> > hast du denn erfahrungen mit grossen projekten?
>
> Ja. Aber alle großen Projekte wo ich selber beteiligt war, waren in Java.
> C++ waren meist eher kleinere Dinge.
Das könnte einen Grund haben, der nicht für C++ spricht.. *giggle*
> 1. Zerstörung von Objekten nicht "just in time".
> --------------------------------------------------------------------
> Garbagecollection und die Nichtnotwenigkeit sich um Aufräumarbeiten zu
> kümmern mag ein Vorteil sein. Aber die Java-Garbagecollection
> garantiert eben nicht - wie bei Python beispielsweise - die sofortige
Ich glaube, daß das auch nicht von Python garantiert wird. Die gängige
C-Implementierung macht das so, es gibt aber noch andere.
> Zerstörung (bzw. wenigstens den sofotigen Aufruf eines Destruktors)
> wenn das Objekt den Sichtbarkeitsbereich verlässt.
> D.h. durch verspätete destruierung bzw. der Unmöglichkeit einer
> automatischen Destruierung entstehen Ressourcenleaks! Entgegen dem
> Java-Versprechen...
Das kann man jedenfalls durch try-finally nachbauen. Die fehlende
finally-Klausel kann man sicherlich mit einem Werkzeug à la FindBugs
automatisch finden.
Ich gebe zu, daß ein using-Konstrukt, wie es C# hat, noch besser
wäre. Aber die automatische Speicherverwaltung per Referenzzähler
(das, was C-Python macht) hat selbst eine ganze Reihe von Problemen,
so daß sie keine allgemeine Lösung ist.
> 2. Kein impliziter Copycontructor.
> Aber was habe ich gekonnt? Mein B Objekt was per Vererbung ein A
> Object _ist_ wird niemals die private Variable a übernehmen.
In Java würde man das per Delegation angehen.
> 3. Aufruf einer Funktion einer höheren Basisklasse nicht möglich
Naja, wenn dieses Konstrukt möglich und sinnvoll ist, dann muß man so
viel dokumentieren, daß es auf die zusätzliche Methode auch nicht
ankommt.
also erstmal habe ich gesagt dass das ein psychologischerFaktor ist, der
asu dem Schriftbild entsteht und halt dem einem gefällt während der
andere es als kryptisch empfindet. Natürlich macht das die
Funktionsweise nicht schlechter deswegen! Wobei ich sagen muss, wenn ich
an Tabs vs. Leerzeichen denke wird das eventuell schon unschön. Wie
verhält sich da Python?
>Das kann denke ich auch ein Lisp-Entwickler bestätigen.
Lisp ist extrem, weil einfach alles in runden Klammern hängt.
> Hier ist die Summenbildung über eine Collection in Java:
>
> int sum(Collection<Integer> collection) {
> int sum = 0;
> for (Integer i : collection) {
> sum += i;
> }
> return sum;
> }
>
> Und in Python:
>
> def sum(seq):
> sum = 0
> for i in seq: sum += i
> return sum
>
> 4 statt 7 Zeilen.
Man kann es in Java auch so schreiben:
> int sum(Collection<Integer> collection) {
> int sum = 0;
> for (Integer i : collection) sum += i;
> return sum;}
Man kann also auch in Java so programmieren wenn man will, aber ich will
das ehrlich gesagt nicht.
> das ist eine rein psychologische Sache. Es bedarf da keines logischen
> Grundes... vielen gefällt das "Schriftbild" einfach nicht.
Ok, ich gebe zu ich liebe Python. Meine Lieblingssprache, solange es
nicht auf Performance ankommt und ich sie nehmen kann.
> Also ich sehe das nicht so eng... Da arbeitet man einmal mit Common
> Lisp, das andere mal mit Scheme. Verschiedene Sprachen, aber extrem
> ähnlich. Dann arbeitet man mit C oder C++... Zu sagen die würden sich
> syntaktisch fundamental unterschieden wäre auch gewagt.
Aber mit c und C++ gabs doch ähnliche Probleme!
Viele ältere C-Programmierer programmieren halt eigentlich C statt C++.
Da gibt's einen Haufen Bibliotheken wo das so ist...
Oder C Programmierer programmieren statt in Ansi-C in K&R-C. *schüttel*
_Das_ sieht erst aus...;-)
> Hier ist die Summenbildung über eine Collection in Java:
> int sum(Collection<Integer> collection) {
> int sum = 0;
> for (Integer i : collection) {
> sum += i;
> }
> return sum;
> }
Das Beispiel ist fast unfair. Denn diese Kontruktion gibts erst seit
Java1.5. Früher[tm] war das noch krampfiger.
>> Denn oft sind genau diejenigen die die Formatierungspflicht bei
>> Python bemänglen die, die auf exakte Einhaltung eines Styleguides
>> mit definierter Anzahl von Lehrzeichen als Einrückung und richtiger
>> Klassersetzung (sollte Klammersetzung heissen) bestehen.
> Was ich im Übrigens auch für wichtig halte.
Definitiv!
Jedoch prallen da oft andere Geschmäcker aufeinander.
Beispiele.
Folgendes halte _ich_ für schlechten Stil.
if (...) {
} else{
}
Besser:
if (...) {
}
else{
}
Damit else auf gleiche Einrückungsebene wie das zugehörige if.
Und
a = langerAudruck +
nochEinlangerAusdruck +
nochEinGanzLangerAusdruckzumSchluss;
ebenfalls. Besser wäre hier:
a = langerAudruck
+ nochEinlangerAusdruck
+ nochEinGanzLangerAusdruckzumSchluss;
> Wie verhält sich da Python?
Unschön! Das muss man zugeben. Aber praktisch ist es kein Problem, wenn
man konsequent nur mit Tabs oder nur mit Leerzeichen arbeitet. Fast
Jeder Editor kann das ja.
1 Tab entspricht 8 Leerzeichen
Was dann konfus wird, wenn man Tabweite von Beispielsweise 2 hat.
def function(self):
anweisung1 #mit tab
anweisung2 #mit leerzeichen
gibt keinen Syntax error, aber das hier:
def function(self):
anweisung1 #mit tab
anweisung2 #mit leerzeichen
Ich hab nicht alles gelesen, evtl. hat es schon jemand geschrieben.
Betriebssystemnahe Sachen wie Gerätetreiber, Kernelmodule,
Interrupt-Handler oder so gehen mit Java nicht.
Bis Java5 hat man ohne Zusatz-Lib nicht mal die Info über den freien
Plattenplatz im API.
--
Heiner Kücker
www.heinerkuecker.de
www.control-and-command.de
Nicht dass ich das so machen wuerde, aber es gibt einen Grund warum LoC
nicht in "Zeilen" definiert ist:
int sum(Collection<Integer> collection) {
int sum = 0;
for (Integer i : collection) { sum += i; }
return sum; }
Gruss
Bernd
Ack. Ich wünsche mir z.b. hierarchische packages, das würde der package
visibility schon einiges helfen.
Gruss
Bernd
nun, ich bin mit Pascal groß geworden, deswegen habe ich gerne Marker
zumindest für das Ende eines Blocks... und das einzige wo ich sowas
nicht hatte war GWBasic oder Assembler... nicht unbedingt die besten
Paten für Python finde ich. Aber wie gesagt, das hat mit Logik wenig zu tun.
> Bsp. Ich habe eine Liste von Objekten, die alle eine ID haben und möchte
> nun ein Dictionary (wie heißt das eigentlich in Java), zum schnelleren
> auffinden der Objekte:
>
> # Konstruieren:
> class A:
> def __init__(self, id):
> self.id = id
> olist = [A(1), A(2), A(3), A(4)]
>
> # Ok, und jetzt mein Problem, das ich in Java nicht so einfach
> # hingekriegt habe:
>
> odict = dict( [(i.id, i) for i in olist] )
>
> Wie würde man das in Java schreiben?
dazu müsste ich erstmal wissen was das ist ;) Es wird wohl eine Liste
von Paaren erzeugen, aber was dict macht weiss ich nicht. Vorallem nicht
warum ich dazu die Klasse A brauche. Ansonsten würde ich sagen dass eine
Map das leistet.
>> 1 Tab entspricht 8 Leerzeichen
>
> Lässt sich das dort nicht irgendwie einstellen ähnlich wie der charset
> am beginn der Datei?
Man kann es dem Interpreter übergeben. Das ist aber auch unschön, man
sollte ganz einfach nur mit Leerzeichen arbeiten, dann hat man das
Problem nicht. Das gilt auch für andere Sprachen, für Python aber ganz
speziell, weil die Einrückung hier Teil der Syntax ist.
Gruss,
Raffi
--
Come to think of it, there are already a million monkeys on a million
typewriters, and Usenet is *nothing* like Shakespeare!
her...@raffael.ch · PGP Key 5D1FF5F4 · http://www.raffael.ch/
Ich wollte ja eigentlich mich nicht wieder mit deiner gefplgegten
Formatierung auseinandersetzen, aber ne Frage hab ich doch:
> for( final java.lang.Integer i : collection )sum += i;
^^
Wieso denn Leerzeichen vor den Klammern aber nicht danach?
Gruss
Bernd
in der Ähnlichkeit der Syntax sehe ich kein Problem.
> Viele ältere C-Programmierer programmieren halt eigentlich C statt C++.
> Da gibt's einen Haufen Bibliotheken wo das so ist...
Das ist schon eher ein Problem... besonders wenn dann tricks angewandt
werden die in der einer Sprache zur Sprache gehören in der anderen aber
emuliert werden müssen... Oder wie war nochmal der Spruch mit Lisp
stecke in allem drin? ;)
> Bsp. Ich habe eine Liste von Objekten, die alle eine ID haben und möchte
> nun ein Dictionary (wie heißt das eigentlich in Java), zum schnelleren
> auffinden der Objekte:
>
> # Konstruieren:
> class A:
> def __init__(self, id):
> self.id = id
> olist = [A(1), A(2), A(3), A(4)]
Wenn du olist nur hast, um sie in odict zu stecken, könntest du auch
olist = (A(i) for i in xrange(1, 11))
benutzen. Auch würde ich die [] bei odict weglassen, weil das ein
unnötiges Array erzeugt. Also einfach
odict = dict((o.id, o) for o in olist)
> Wie würde man das in Java schreiben?
public class A {
public int id;
public A(int id) {
this.id = id;
}
}
List<A> olist = Arrays.asList(new A(1), new A(2), new A(3), new A(4));
/* hat aber nicht die gleiche Semantik, da olist jetzt nicht
änderbar ist. Eigentlich wäre es daher: */
List<A> olist = new ArrayList<A>(4);
olist.add(new A(1));
olist.add(new A(2));
olist.add(new A(3));
olist.add(new A(4));
Map<Integer, A> odict = new HashMap<Integer, A>(4);
for (A a : olist) {
odict.put(a.id, a);
}
@Jochen: Der Ausdruck mit dem nachgestellten for ist eine
List-Comprehension a la Haskell, die sich genauso liest wie eine
mathematische Mengenbeschreibung.
set = { x | x > 10 }
=>
set = (x for x in numbers() if x > 10)
mit
def numbers():
n = 0
while True:
yield n
n += 1
was natürlich nicht endlich ist. Man möge daher nie versuchen, obiges
set in ein Set-Objekt oder eine Liste oder Tupel zu verwandeln.
--
Stefan Matthias Aust
> Folgendes halte _ich_ für schlechten Stil. [...]
Was du für schlecht hältst, ist der von Sun empfohle Stil (sie haben es
gewagt, einen Styleguide zu schreiben, der recht weit akzeptiert ist)
und daher würde ich sagen, man gewöhnt sich an allem (sogar dem Dativ)
und wer Rom kommt, soll es wie die Römer treiben oder so ähnlich.
Bei C# muss ich mich daher auch an das IMHO abartige
if (...)
{
bla();
}
gewöhnen :)
> Und
>
> a = langerAudruck +
> nochEinlangerAusdruck +
> nochEinGanzLangerAusdruckzumSchluss;
>
> ebenfalls. Besser wäre hier:
>
> a = langerAudruck
> + nochEinlangerAusdruck
> + nochEinGanzLangerAusdruckzumSchluss;
Da sage ich die erste Variante ist besser (schon allein daher, da sie
die einzige für Ruby und ich glaube auch Python mögliche ist) weil man
eben sieht, dass die Zeile noch weitergehen muss, da das zweite Argument
des Operators fehlt.
--
Stefan Matthias Aust
> Nicht dass ich das so machen wuerde, aber es gibt einen Grund warum LoC
> nicht in "Zeilen" definiert ist:
>
> int sum(Collection<Integer> collection) {
> int sum = 0;
> for (Integer i : collection) { sum += i; }
> return sum; }
Das ist aber nicht der Stil, wie man Java schreibt (ich hätte das
Python-Beispiel auch in eine Zeile quetschen können) und daher nicht
gültig. Tatsächlich sieht es so aus wie Code, den Stefan Arbeitsspeicher
verbrochen haben könnte. Dort hätten wir dann aber java.util.Collection
und java.lang.Integer für maximale Unlesbarkeit gelesen :)
--
Stefan Matthias Aust
>>Das kann denke ich auch ein Lisp-Entwickler bestätigen.
>
> Lisp ist extrem, weil einfach alles in runden Klammern hängt.
Nun, was ich meinte ist, dass ein Lisp-Entwickler auf die Klammern nicht
achtet. Niemals (so hoffe ich) stehen sie alleine in einer Zeile, also
der Code ist immer
(define (f n)
(if (= n 0)
1
(* (f (1- n)) n)))
und nicht
(define (f n)
(if (= n 0)
1
(* (f (1- n)) n)
)
> Wie bestimmt man denn in Python, ob das Verzeichnis mit
> Streuspeicherung oder mit Bäumen implementiert werden soll?
Indem man eine entsprechende Implementierung benutzt. Wer { } als
Kurzform für ein Dictionary-Konstruktor benutzt, bekommt immer eine
HashMap. Wer dict() benutzt, ebenfalls. Wer
machs_mir_mit_baeumen(a=3, b=4)
benutzt und obige Funktion entsprechend implementiert oder eine passende
Bibliotheksfunktion importiert, der hat eben eine andere Implementierung
des Map-Konzepts. Entscheidend ist, der Zugriff kann dank
Operator-Überladung von [] immer syntaktisch auf die selbe Weise gemacht
werden.
--
Stefan Matthias Aust
Wenn man auf diese - sagen wir mal unerfahrene - Art und Weise an eine
Sprache herangeht, dann kommen halt keine guten Ergebnisse raus. Das liegt
dann aber weniger an der Sprache (es sei denn die Sprache ist so kompliziert
dass man sie nur als Guru überhaupt benutzen will :)
> in python halt odict[gesucht]
Das hat nun wirklich nichts mit Python Vorteilen zu tun.
Gruss
Bernd
das nicht, aber die Syntax sagte mir trotzdem nicht viel, weil ich es
nicht gewohnt bin und ganz falsch lag ich ja auch nicht.
> Also ich kann später einfach über
>
> odict[id] auf das jeweilige Item zugreifen, dies gibt mir sozusagen einen
> Index, (wobei hier ziffern aus dem integer Raum kommen, die eigentlich
> keine Bedeutung haben, außer das Objekt eindeutig zu identifizieren).
du übersiehst aber eventuell einen wichtigen Punkt. Du musst dienen Stil
der Sprache anpassen. Python in Java zu programmieren macht weder dich
glücklich noch Leute die das lesen sollen.
sieh bitte nicht Stefan's Formatierung als ein Beispiel für das normale
Layout von Code in Java an. Stefan hat da seine eigenen Regeln, die
viele als schlecht lesbar empfinden.
übrigens geht zweiteres auch in Groovy nicht gut.
Geht das denn, kann man mehr als einen Block oder Statement in einer Python
Zeile haben?
Gruss
Bernd
ja gut, aber bei Variante 1 musst die ständig die runden Klammern
zählen. Es gibt schon einen Grund warum der Editor bei... ich glaube Dr.
Scheme immer so aufdringlich die Klammern hat blinken lassen. Die zweite
Variante finde ich lesbarer, weil ich diesen Stil eher gewohnt bin.
Befehle lassen sich durch ";" trennen. Nach dem ":" darf ein Befehl bzw.
eine durch ";" getrennte Sequenz von Befehlen folgen.
--
Stefan Matthias Aust
> Was du für schlecht hältst, ist der von Sun empfohle Stil
Hab ich doch gesagt: die Geschmäcker gehen auseinandern.
> (sie haben es
> gewagt, einen Styleguide zu schreiben, der recht weit akzeptiert ist)
Und ich wage ihn zu kritisieren. Nicht aus Prinzip, sondern weil es
bestimmte Gründe dafür gibt.
>> a = langerAudruck +
>> nochEinlangerAusdruck +
>> nochEinGanzLangerAusdruckzumSchluss;
>>
>> ebenfalls. Besser wäre hier:
>>
>> a = langerAudruck
>> + nochEinlangerAusdruck
>> + nochEinGanzLangerAusdruckzumSchluss;
Ich weiss das viele Leute ersteres bevorzugen, deswegn nahm ich es ja
als Beispiel.
Vorteil von 2. ist dass jede Zeile alleine eine ungültige Zeile ist.
D.h. kommentiert man den Ausdruck aus, vergisst aber die letzte Zeile,
dann wird in der oberen Variante nochEinGanzLangerAusdruckzumSchluss;
als gültiger Ausdruck trotzdem ausgewertet. Man denke vor allen
daran, dass es eine Funktion sein kann.
Ausserdem ist zweites Beispiel besser wenn man lange Zeilen schreibt.
Hier sieht man den Operator ohne Scrollen zu müssen.
(ja, ich weiss 80 Zeichen und so...aber wer druckt noch Code wirklich
aus oder arbeitet mir VT100 und vi...)
Nein, ist es nicht. Im objektorientierten System mit Vererbung ist es
ein schlechtes Design wenn ich auf die super-Methode nicht meines
direkten Vorfahrens zugreife, sondern die von dessen Vorfahren.
Das ist so und das bleibt so. Das ist weder leserlich, noch wartbar und
damit der Beginn des Todes einer Klassenhierachie.
Grüße
Dirk
http://www.heinerkuecker.de/Xrpp.html
http://control-and-command.de/zip/Xrpp.zip
In dem zip-File gibt es die Klassen
ByteStr
ByteStrBuff
Heiner
www.heinerkuecker.de
Hast Du das hier schon mal gelesen ?
C-Hasser in 10 Tagen
http://www.math.uni-bremen.de/~thielema/CHater.html
Heiner
www.heinerkuecker.de
Gruß
Wolfgang R.
> C-Hasser in 10 Tagen
Das ist eben der Unterschied...Javahasser wird man schneller...;-)
Ernsthafter:
C ist nicht C++ und auch C++ ist keine schöne Sprache.
Aber eine recht mächtige.
> Hast Du das hier schon mal gelesen ?
"Es gibt etliche Sprachen, die sich als Fortführung von C verstehen oder
die auf wesentlichen Schwächen von C aufbauen: C++, Java, C# usw. Diese
eignen sich allein aufgrund ihrer Syntax gut zum Hassen."
>
> Ernsthafter:
> C ist nicht C++ und auch C++ ist keine schöne Sprache.
> Aber eine recht mächtige.
>
Kaum ein Mensch will heute noch eine Eierlegende-Woll-Milch-Sau-Sprache.
Es geht doch darum, dass jede Sprache ihr Anwendungsgebiet hat. Für
betriebliche Informationssysteme gibt IMHO keine besser geeignete
Sprache als Java. Ich will mich dabei hauptsächlich auf meine
Bussinesslogik konzentrieren, und mir keine Gedanken darüber machen wie
ich meinen Speicher wieder aufräumen muss, so wie ich es in C/C++ machen
muss.
Umgekehrt würde ich nicht umbedingt Embedded Systeme in Java
programmieren wollen, da will man so viel rausholen wie geht, da macht
für mich "Zeiger-Schubsen" Sinn. Genau so wenig würde ich ein
Datenbanksystem für große Systeme in Java machen.
Python finde ich zwar eine ganz nette Sprache, aber für mich ist es noch
keine ernsthafte Kongurenz zu Java. Das ist sicherlich eine persönliche
Sache, aber ich bin kein großer Fan von dynamischen Sprachen. Außerdem
finde ich es etwas seltsam, dass man bei jeder Objekt-Methode self als
ersten Parameter mitgeben muss und das es keine Namespaces oder Packages
gibt. Aber sicherlich gibt es auch einige sehr nette Sprachfeatures wie
yield, List comprehension oder Function Decorators.
Nimm es nicht persönlich, aber hast du schon mal daran gedacht den Job
zu wechseln und etwas zu machen das sich mit C++ besser lösen lässt, als
hier Java-Bashing zu betreiben ;).
mfg
Andreas
> Nimm es nicht persönlich, aber hast du schon mal daran gedacht den Job
> zu wechseln und etwas zu machen das sich mit C++ besser lösen lässt, als
> hier Java-Bashing zu betreiben ;).
Dann machts doch keinen Spass mehr. Wenn man täglich mit C++ zu tun hat
und zwar sowohl mit eigenen dahingesch...luderten Code als auch mit dem
von anderen (keine aufgeräumten Open-Source-Projekte...sondern
kommerzielle Software...;-)) dann würde ich den ganzen Tag auf C++
kotzen...;-)
Aber irgendwie versöhnt mich dann immer die monatliche Überweisung...;-)
Da programmiert man auch schon mal Visual Basic falls gewünscht.
(war mal ein durchaus ernsthaftes Projekt, zwar nicht super groß, aber
egal.)
Das Problem ist, dass Projekte wachsen, da noch ein bisschen aufgbohrt,
da noch was drangeschraubt. Und schwuppdiwupp hat man schlechtes Design.
Wenn dann die Sprache noch gutes Design auch in solchen "Notfällen"
(Termindruck, keine schnelle Alternative) erzwingen will, hat man die
Sprache halt gegen sich...und dann entstehen solche Threads. ;-)
> Nein, ist es nicht. Im objektorientierten System mit Vererbung ist es
> ein schlechtes Design wenn ich auf die super-Methode nicht meines
> direkten Vorfahrens zugreife, sondern die von dessen Vorfahren.
> Das ist so und das bleibt so. Das ist weder leserlich, noch wartbar und
> damit der Beginn des Todes einer Klassenhierachie.
Die Alternative wäre eine Copy-und-Paste-Orgie.
Entweder Klasse komplett parallel mit ähnlicher Funktionalität (woraus
es praktisch hinausgelaufen ist) - aber ebensowenig schön.
Oder die Luxuslösung mit kompletten Redesign: Aufwändig, erfordert neue
Tests etc. pp.
Ohne konkrete Beispiele zu kennen kann man dir nichts raten, aber aus meiner
Erfahrung kann ich dir hier nicht zustimmen. Wenn du die Funktion einer
ueberschriebenen super methode nicht nutzen kannst, wieso kannst du deren
super methode nutzen (woher kennst du diese wenn die kapselung sauber ist).
In der Regel ist es generell sauber Funktionen die Ableitungen benutzen
koennten in eine eigene helper methode zu packen, und diese aufzurufen. Dann
kann man diese erstens wiederverwenden und zweitens mit feiner granularität
ueberschreiben.
Gruss
Bernd
Also ich habe bisher immer den Eindruck gehabt dass einem Java in genau den
Situationen dank GC und managed Code den Arsch rettet. Mach mal ein grosses
C++ Projekt (und suche ne Memory Corruption), dass weisst du was ich meine.
Dinge wie "fehlendes" super.super sind ja notfalls wenn es sein muss mit 2-3
Zeilen als Work-around geloest, man kann nicht davon reden dass Java einem
in dem Fall ausbremst. (aber man kann mit sicherheit sagen dass in vielen
stellen in denen man sich ausgebremst fuehlt man besser eine andere Loesung
nehmen sollte)
Gruss
Bernd
> Also ich habe bisher immer den Eindruck gehabt dass einem Java in genau den
> Situationen dank GC und managed Code den Arsch rettet. Mach mal ein grosses
> C++ Projekt (und suche ne Memory Corruption), dass weisst du was ich meine.
Ich weiss was du meinst.
Im Zusammenspiel mit vielen anderen Programmieren rettet das wirklich
einen den Arsch. Allerdings fehlt die Gegenprobe...
Wenn ich meinen eigenen Code kenne, dann weiss ich wo ich suchen muss
und habs auch fast[1] immer gefunden.
Aber fremden Code zu debuggen ist Sackgang.
[1] multithreading mit posix threads und sockets unter IRIX, suid also
das ganze Programm unter Unix mit C-Libs etc. Die Memory Corruption war
nicht zu finden und das Programm stützte nichtderterministisch ab.
Letztendlich habe ich das in Python gemacht. Genauer das war mein erstes
Projekt in Python auf Anraten meines damaligen Kollegen. Er hatte Recht.
Dass Java Threading eingebaut hat ist ein großes Plus für Java.
Aber ansonsten habe ich schon einen Raytracer inclusive (recht
spartanischer, aber immerhin vier Ansichten, ) GUI gechrieben.
Geht alles...
Eine Copy-and-Paste-Orgie ist mit Sicherheit falsch. Für mich riecht das
weiterhin nach einem falschen Design. Warum leitest du überhaupt von
diesem Objekt und nicht von dessen Vater ab? Ist das wirklich "ein"
Objekt oder stecken da vielleicht zwei gleichzeitig drin? Sozusagen der
Wohnzimmertisch und der Wohnzimmerstuhl und du brauchst nun zwar den
Wohnzimmertisch und seine Eigenschaften und parallel vielleicht doch auf
jeden Fall einen normalen Stuhl.
Solche Ideen kommen mir ... und das ist definitiv Murks, grosser Murks
wie mal jemand sagte.
Desweiteren könnte es sein, dass du deine Probleme besser mit einigen
DesignPattern lösen könntest. Delegator fällt mir da direkt mal ein.
Grüße
Dirk
Aber wieso führt sowas dann zu Kritik an Java? Mh, ich würde den
Designer aus dem Fenster springen lassen, denn solche Leute sind doch
dann für exorbitant teure Projekte zuständig.
Grüße
Dirk
Wenn ich sowas lese, dann kommt mir das Grauen und gleichzeitig die
Sicherheit, dass genau solche Leute wie du für schlechtes Design
verantwortlich sind.
Es gibt null Gründe warum ein grosses Projekt schlechtes Design haben
sollte. Es gibt tausend Gründe warum man nicht unter Termindruck auf
Quick-and-Dirty zurückgreifen soll. Denn dann entstehen nicht solche
Threads wie hier (überflüssig wie ein Kropf) sondern dann beginnt der
Todeskampf des Quelltext. Der nächste Entwickler wird die Hände über den
Kopf zusammenschlagen und die Effizienz in der Softwareentwicklung in
diesem Unternehmen tendiert gegen null.
Daraus folgt dann direkt, dass mehr Leute gebraucht werden und dann wird
wieder "Fachkräftemangel" geschrien.
Und du willst, dass Java diesen Quick-And-Dirty-Krams noch besser
unterstützt? Du solltest ganz schnell den Job wechseln, Gärtner wäre
auch nicht gut, die armen Pflanzen.
Sorry, aber sowas regt mich auf. Die Denkweise von dir zeigt mir, dass
Java und seine Paradigmen viel schwerer zu erlernen sind, als manche
glauben. Und deine Denkweise zeigt auch, dass Software-Entwicklund und
gutes Architektur-Design etc. kein Hokuspokus sind, dass jeder erlernen
könnte. Du stehst auf jeden Fall auf der anderen Seite des Zaunes.
Grüße
Dirk
<gemütlich zurücklehn> Will noch jemand Popcorn und ein Bier?
SCNR, Thomas.
> <gemütlich zurücklehn> Will noch jemand Popcorn und ein Bier?
Ein Hefeweizen bitte. Der Thread hat Potential. ;-)
Gruß,
Michael
Ich nehme auch ein Hefeweizen ... Popcorn lieber nicht, Nachos wären okay.
Dann habe ich auch mal Zeit zwischen dem Reden zuzuhören ;)
Aber jetzt mal ernsthaft: Bin ich der einzige der nicht verstehen kann
wieso schlechtes Design in einem Projekt als Grundlage der Begründung
für neue Features im Java-Sprachumfang verwendet wird, welche schlechtes
Design nur weiter fördern?
Grüße
Dirk
>Aber jetzt mal ernsthaft: Bin ich der einzige der nicht verstehen kann
>wieso schlechtes Design in einem Projekt als Grundlage der Begründung für
>neue Features im Java-Sprachumfang verwendet wird, welche schlechtes
>Design nur weiter fördern?
Nee, du bist nicht der einzige. Ich war im Laufe dieses Threads zigmal
versucht Thomas Thiele einfach zu plonken nur um letztlich meine Nerven zu
schonen, weil mir bei diesem Thread eigentlich mit jedem seiner Postings
die Hutschnur hochging.
Das fängt schon mit dem Eingangsposting an: Wer eine kritische Diskussion
über die Schwächen einer Sprache beginnen möchte, sollte Experte in dieser
Sprache sein. TT ist das in Bezug auf Java ganz offensichtlich nicht, da
er ja noch nicht mal in seinen kurzen Pseudo-Code-Fetzen annähernd
korrekte Java-Syntax verwenden kann. (Penible Zeitgenossen werten schon
die Schreibweise JAVA im Betreff als Zeichen dafür, es mit einem
Java-Neuling zu tun zu haben.)
Dann ist da noch was TT in seinem Eingangsposting kritisiert: Den
Copy-Konstruktor hat er schon im September vor beinahe 2 Jahren vermisst,
und etliche Antworten darauf erhalten, nicht bloß von mir:
http://groups.google.de/group/de.comp.lang.java/msg/f7135d943a18b75f . In
einer Sprache, die auf alle Objekte nur über Referenzen zugreift und keine
echten Value-Objekte kennt, ist ein automatischer Copy-Konstructor
ziemlich unnütz. Und TT weiß ja eigentlich auch welchen Krampf man sich
mit einem solchen Konstruktor einhandelt:
http://groups.google.de/group/de.comp.lang.iso-c++/msg/2b19c6fa9b880d09 .
Warum er ihn dann in Java dennoch haben will, ist mir schleierhaft, zumal
er ja jeden Kritikpunkt der in der Philosophie von Java begründet ist
eigentlich ausschließt. Und der autom. Copy-Konstruktor ist nicht nur eng
mit dem Operator-Overloading verknüpft, sondern auch aus den gleichen
Gründen, nämlich zu leicht missverständlichen Code schreiben zu können,
aus Java herausgehalten worden.
Naja, zu super.super.foo() kann ich dann nur sagen, dass mir beim bloßen
Gedanken, sowas nötig zu haben, schon das Grauen kommt. (Was soll
eigentlich in folgendem Fall passieren:
class A {
int foo() {...}
}
class B extends A {
int foo() {... super.foo(); ...}
int bar() {...}
}
class C extends B {
int foo() {... super.super.foo(); ...}
}
Und jetzt wird B refaktoriert, weil noch etwas B-ähnliches dazu kommt:
abstract class AbstractB extends A {
int foo() {... super.foo(); ...}
abstract int bar();
}
class B extends AbstractB {
int bar() {...}
}
class BB extends AbstractB {
int bar() {...}
}
Was soll das super.super.foo() in C jetzt machen? Ruft es immer noch
A#foo() auf?)
Na und die Behauptung wegen der Lazy-GC seien Resourcenleaks unvermeidlich
haben ja schon genug Leute widerlegt.
Nun wenn ich mich auf dieselbe Ebene wie TT stellen würde, dann würde ich
mit meinen mageren C++ Kenntnissen mal in einer C++ Gruppe fragen, was die
wirklichen Einschränkungen von C++ seien. Da fiele mir mal als allererstes
ein, dass man in C++ kein Metaprogramming machen kann, wie es in Java zur
Build-Time durch Bytecode-Enhancer schon immer und seit 1.5 durch die
Instrumentation API auch zur Laufzeit möglich ist.
Und kann ich in C++ von einem Objekt auf das ich nur eine Referenz
erhalten habe, dessen Schnittstelle herausfinden? Und so wie Beans auch in
Skripten in meiner Anwendung benutzen? Überhaupt: Kann ich C++ ähnlich dem
BSF leicht eine Scripting-Sprache in meine Anwendung einbauen, die dann
Zugriff auf meine Anwendungsobjekte erhalten kann? Für all das ist
Reflection nötig und die gibt es AFAIK bei C++ nicht.
Nun mag es dennoch sein dass es sowas gibt, ich kenne C++ nicht genug um
es zu kritisieren, und ich würde mir wünschen, dass TT _meiner_
Lieblingssprache solange er kein Experte in ihr ist, denselben Respekt
entgegenbringt, wie ich seinem geliebten C++ und Python und was noch alles.
cu
>"Ralf Ullrich" <ne...@jnana.de> writes:
>>Da fiele mir mal als allererstes ein, dass man in C++ kein
>>Metaprogramming machen kann, wie es in Java zur Build-Time
>>durch Bytecode-Enhancer schon immer und seit 1.5 durch die
>>Instrumentation API auch zur Laufzeit möglich ist.
>
> C++ erlaubt Metaprogrammierung
Danke für den Hinweis, aber wie ich feststellen muss, versteht man wohl
heute unter "Metaprogrammierung" etwas anderes als ich 1988 gelernt habe.
Ich zitiere:
*Metaprogramme* behandeln andere Programme als Daten. Die Objekte, die von
Metaprogrammen manipuliert werden, sind selbst Programme.
*Metaprogrammierung* ist somit als Erstellung von Programmen definiert,
die die Manipulation von anderen Programmen zum Ziel haben.
(aus Gustaf Neumann - Metaprogrammierung und Prolog - ISBN m3-925118-94-2)
Damit fallen Java-Profiler, AspectJ, JDO-Bytecodeenhancer, Instrumentation
und ähnliches, wie z.B. das annotationsgesteuerte JAXB 2.x, unter diese
Definition von Metaprogrammierung, aber das worauf du in Bezug auf C++
verwiesen hast, scheint mir nicht darunter zu fallen. Aber ich kann mich
täuschen, wie gesagt ich kann C++ nur rudimentär. (Achja, die Hotspot-VM
selbst ist natürlich auch ein Metaprogramm, genauer sogar ein
Metaübersetzer und -interpreter, da sie Bytecode-Programme als Daten
behandelt.)
Die neue Begriffsverwendung von "Metaprogrammierung", die sich auch in der
Wikipedia findet (http://de.wikipedia.org/wiki/Metaprogrammierung) und der
Verwendung bei C++ entspricht, ist dagegen bloße Code-Generation. Der
wesentlich Unterschied, ist, dass C+-Metaprogrammierung prinzipiell aus
beliebigen Daten Programmcode generiert, während die Metaprogrammierung,
so wie ich sie kenne, aus normalem Programmen, die nicht extra für diesen
Schritt vorbereitet sind, neue erweiterte Programme erzeugt, also
tatsächlich Programme als Eingabedaten entgegennimmt.
Ein einfach vorzustellendes Beispiel ist da ein Metaprogramm M, dass einem
Programm P Tracing-Funktionalität hinzufügt, sodass jeder Methodenaufruf
bei Einsprung und Rücksprung jeweils eine entsprechende Tracing-Meldung
ausgibt. M kann dabei das Programm P entweder interpretieren und während
der Interpretation die Meta-Funktionalität liefern, oder so zu einem neuen
Programm übersetzen, dass die Meta-Funktionalität in das Programm
integriert wird. In letzerem Fall ist das Ergebnis ein neues Programm
P_trace, dass durch weitere Metaübersetzer noch weiter erweitert werden
kann.
cu
Ansonsten gibt es immer ein paar ecken und Kanten an jeder Sprache.
Nur andauernd nach neuen Features zu rufen ist wirklich nicht immer die
Lösung aller Probleme. Hin und wieder ist auch einfach ein überdenken
des Lösungsansatzes schon hilfreich :)
peter
> Aber jetzt mal ernsthaft: Bin ich der einzige der nicht verstehen kann
> wieso schlechtes Design in einem Projekt als Grundlage der Begründung
> für neue Features im Java-Sprachumfang verwendet wird, welche schlechtes
> Design nur weiter fördern?
Der von dir zitierte Teil war zumindest nach meinem dafürhalten keine
Lobeshymne auf Sprachen die schlechtes Design gutheißen, sondern las
sich für mich eher wie eine simple Bestandsaufnahme ohne Wertung.
Ist halt so: Wenn du unter Termindruck, Quick&Dirty willst, aber dir die
Sprache das nicht durchgehen lassen will, steht dir die Sprache im Weg.
Und ich möchte hinzufügen: Wowereit!
Auch wenn es mal nervt, ist es doch gut, wenn man in dem Moment einer
gewissen Scheißegal-Haltung, weil der Kunde ohne Ende Druck macht und
man den einfach nur losweden will, wenigstens ein bischen in seinem
Schaum gebremst wird, damit man sich nicht noch mehr Scheiße einfängt,
die einem später dreimal so heftig um die Ohren fliegt.
Gruß,
-Wanja-
--
Ada Byron, die Lochkarten für Babbages "Difference Engine" vorbereitete,
gilt als die erste Programmiererin der Weltgeschichte. Sie hat auch das
Verhaltensmuster für alle nachfolgenden Programmierer vorgegeben: Sie
trank und schluckte Drogen.