const in Java und interface's ...



  • Also eine der ersten Grundlagen in OOP, die ich gelernt habe, ist daß ein Container einer abgeleiteten Klasse kein Container der Basisklasse ist (sonst könnte man ja auch einen vector<Auto> als vector<Fahrzeug> übergeben und bekommt plötzlich Boote dort reingepackt). Und da const kein Java Sprachkonzept ist, dürfte es für den Compiler keinen Unterschied zwischen der Umwandlung vector<Auto> -> vector<Fahrzeug> und vector<test> -> vector<const_test> geben, oder?

    PS: @Namen: alles eine Sache der Gewöhnung - in C++ hat sich nunmal komplette Kleinschreibung mit Unterstrichen durchgesetzt 😉



  • Schreibstil:
    Geht mir genauso. Auch nach Monaten C++ ist das alles immernoch häßlich für mich. Dazu kommt auch noch die Formatierung an sich. Unter Java/Eclipse hatten wir einen Formatter der beim Speichern darüber ging, so sah das alles sehr ähnlich aus.
    Jetzt muß ich mir C++-Code von Generationen von Entwicklern ansehen, die alle so platzraubend und komisch formatieren (und das ist nur die Formatierung)... 🙂

    Du kannst in Java in den Vector jedes 'Object' reinschmeissen. Ob das guter Stil ist, kommt auf die Situation an.
    Für mich ist es OK, wenn der Vector 'meineFahrzeuge' heißt und Instanzen von 'PKW', 'Motorrad' und 'Tretroller' enthält, wobei alle am besten von 'Fahrzeug' erben sollten.
    Je nach Kontext sind vielleicht sogar 'Boot' und 'Drachenflieger' OK.
    In anderen Situationen sollten vielleicht sogar ausschließlich 'PKW' drin sein, durch die Sprache wirst Du da aber nicht festgelegt, außer Du nimmst ein Array von 'KFZ', was ich aber nur selten mache, weil ein Vector viel flexibler ist.



  • SammyRukka schrieb:

    Du kannst in Java in den Vector jedes 'Object' reinschmeissen. Ob das guter Stil ist, kommt auf die Situation an.
    Für mich ist es OK, wenn der Vector 'meineFahrzeuge' heißt und Instanzen von 'PKW', 'Motorrad' und 'Tretroller' enthält, wobei alle am besten von 'Fahrzeug' erben sollten.

    Wenn ich auf globaler Ebene einen vector<const_test> hätte, wäre es ja vorstellbar, dort test's reinzuwerfen. Aber umgekehrt in einen vector<test> ein const_test (das eventuell nur gar nicht die set-Methoden definiert hat, die ich im Hauptprogramm benötige) zu packen, ist eine andere Sache.

    PS: Wenn der Vector wirklich nur 'Object'e ohne irgendeine Typkontrolle enthält, ist's sogar noch schlimmer - da wird der Nutzer ja gezwungen zu casten, um die Objekte sinnvoll verwenden zu können.



  • Naja, sauber zu arbeiten lohnt sich halt immer.
    Auch hier habe ich eigentlich niemals das Problem gehabt, das ich nicht gewußt hätte, was ankommt. Im Gegenteil, manchmal braucht man soetwas ja auch (oder meint das zumindest). Das sind die Fälle, bei denen man in C++ dann Void-Pointer benutzt, da finde ich die Java-Lösung besser.
    Das wiederspricht ja auch nicht der OO. Wenn Du da sicher sein willst, dann kannst Du ja auch eine 'KfzListe' implementieren, die die eigentliche Liste und die speziellen Funktionen kapselt.
    Ach ja, toString() können sie in Java alle, da brauchst Du keinen Cast! 🙂

    Und zu dem global habe ich so eine andere Meinung. Das ist wie static-Attribute etwas, auf das in 90% der Fälle Höchststrafe stehen sollte.

    Außerdem finde ich schon, daß Java typsicher ist. Wenn Du anderer Meinung bist, dann hast Du noch niemals in Smalltalk programmiert - und das ist immerhin die objektorientierte Sprache schlechthin!

    ---

    Aber letztendlich wird das alles sehr offtopic (auch wenn ich ganz interessant finde). Letztlich bleibt zu sagen, daß es für const in Java keinen direkten Pendant gibt, aber halt auch nicht geben muß.
    Wenn alles in C++ und Java gleich laufen würde und man nur die Vokabeln getauscht hätte, dann hätte man sich das auch sparen können.
    In der Gesamtheit läßt sich aber auch alles lösen, nur halt auf andere Art - genauso paßt dazu das Thema 'multiple Vererbung': Die einen sagen 'braucht Java nicht', die anderen 'kann Java' nicht. Beides ist wahr.



  • SammyRukka schrieb:

    Sorry, wenn Eure Auto so geschnitten sind, dass sie eine Änderung der Farbe zulassen, dann seid Ihr selbst schuld. Wenn ich die Möglichkeiten zur Verfügung stelle, dann muss ich mich nicht wundern, wenn sie benutzt werden.

    Das ist der Punkt.

    mit const garantierst du, dass getFoo nur ein Foo returned ohne das Objekt selber zu ändern. Es ist einfach eine Garantie die das Objekt gibt.

    Ausserdem ist es schon komisch, einer 'blauen' Instanz des Objekts 'Farbe' per Accessor in einen anderen Zustand versetzen zu können und sich dann zu ärgern, dass jemand von außen das auch kann.
    Warum dann nicht so:
    Objekt 'Autolack' mit final Attribut 'Farbe'. getFarbe beim Auto könnte diesen Antworten oder aber nur auf getAutolack reagieren.

    final bringt dir nichts, ich kann dennoch getFarbe().aendere() aufrufen. Das einzige was funktioniert ist Farbe als immutable zu haben.

    Und im Prinzip ist const genau das: du machst aus einem mutable Objekt mit dem qualifier const einfach ein immutable Objekt.

    Kleines Beispiel:
    Farbe kann immutable sein, aber was wenn man ein Komplexes Objekt hat? zB getMotor().
    Wenn Motor nun Operationen hat die den Motor verändern. Beispiel: reparieren().
    Wie erlauben wir einem Client einen View auf den Motor ohne dass er rumpfuschen darf? Motor kann nicht immutable sein. In Java würde man jetzt eine defensive Kopie machen. Funktioniert auch problemlos. Meistens hat man ja immutable Objekte und wenn mal nicht, dann halt ne defensive Kopie. Tut nicht wirklich weh. Oder man verlässt sich einfach auf den Client Code - auch sehr legitim.

    In C++ hat man diese Gedankengänge aber nicht: man liefert einfach einen immutable Motor. Damit kann Auto vom Client Code verlangen: du darfst den Motor ansehen, aber nicht anfassen.

    Diese Anforderung kann man natürlich auch in die Doku schreiben und das Programm wird nicht kaputt gehen dadurch. Es ist einfach eine Hilfe um gewissen Fehlern vorzubeugen.

    PS:
    Wenn dich schon die Formatierungen stören... Dann bist du wohl sehr penibel. Die wirklichen Unterschiede offenbaren sich erst ein paar Levels tiefer 😉

    zB alleine das Klassendesign ist komplett unterschiedlich...

    @CStoll:
    Java hat keine Templates, ergo wird alles über laufzeit polymorphie gelöst. Generics sind eine automatisierte Variante zum einfügen von den Casts an den richtigen Stellen. Im Prinzip hat man in Java also immer nur vector<Object>



  • SammyRukka schrieb:

    Naja, sauber zu arbeiten lohnt sich halt immer.
    Auch hier habe ich eigentlich niemals das Problem gehabt, das ich nicht gewußt hätte, was ankommt. Im Gegenteil, manchmal braucht man soetwas ja auch (oder meint das zumindest). Das sind die Fälle, bei denen man in C++ dann Void-Pointer benutzt, da finde ich die Java-Lösung besser.

    einen void-Zeiger oder ein allgemeines Object zu verwenden nimmt sich im Endeffekt nicht sehr viel - in beiden Fällen mußt du casten, um etwas sinnvolles mit dem Objekt zu machen (ja, Java reagiert da etwas deutlicher, wenn du falsch castest.

    Das wiederspricht ja auch nicht der OO. Wenn Du da sicher sein willst, dann kannst Du ja auch eine 'KfzListe' implementieren, die die eigentliche Liste und die speziellen Funktionen kapselt.

    Wozu gibt es denn in Java Generics, wenn sie dann doch wieder alles auf 'Object'-Referenzen herunterbrechen? Wenn ich einen vector<KFZ> habe, sollen da nur KFZ's reinkommen und keine Motorboote - indem du erlaubst, diesen als vector<Fahrzeug> oder vector<Object> zu betrachten, unterläufst du die Grundbedingungen (und hast plötzlich doch ein Boot oder gar einen String in dem Vector stehen, der dort nichts zu suchen hat).

    Ach ja, toString() können sie in Java alle, da brauchst Du keinen Cast! 🙂

    Aber toString() ist auch keine eierlegende Wollmilchsau 😉

    Und zu dem global habe ich so eine andere Meinung. Das ist wie static-Attribute etwas, auf das in 90% der Fälle Höchststrafe stehen sollte.

    OK, vielleicht war 'global' die falsche Bezeichnung - ich meinte damit den vector<> in der Main(), der bei Bedarf herumgereicht werden kann.

    Aber letztendlich wird das alles sehr offtopic (auch wenn ich ganz interessant finde). Letztlich bleibt zu sagen, daß es für const in Java keinen direkten Pendant gibt, aber halt auch nicht geben muß.

    OK, das sehe ich ein - auch wenn ich die Gründe dahinter immer noch nicht richtig verstehe (bei mir zieht sich const-correctness normalerweise quer durch alle Programmteile).



  • CStoll schrieb:

    Wozu gibt es denn in Java Generics, wenn sie dann doch wieder alles auf 'Object'-Referenzen herunterbrechen? Wenn ich einen vector<KFZ> habe, sollen da nur KFZ's reinkommen und keine Motorboote - indem du erlaubst, diesen als vector<Fahrzeug> oder vector<Object> zu betrachten, unterläufst du die Grundbedingungen (und hast plötzlich doch ein Boot oder gar einen String in dem Vector stehen, der dort nichts zu suchen hat).

    Es hindert Dich ja auch niemand daran, ein Array zu benutzen oder ein Lsitobjekt (ggf. zu schreiben - nicht kompliziert), dass typsicher ist. Auch hier meine Erfahrung: In den Fällen, in denen ich soetwas brauchte, gab oft auch andere (fachliche) Funktionen, die die Liste gesamt betrafen, so daß sich das sowieso anbot.
    Außerdem muß ich zurückrudern *ASCHE AUF MEIN HAUPT*:
    [Wo ist der Smilie, der ein rotes Gesicht bekommt?!]
    Du hast Recht, Du kannst Listen auch typsicher anlegen, diese Generics (jaja, hast Du ja gesagt) gibt's aber Java 1.5 (glaube ich). Ich habe das noch nie benutzt (ergab sich nie und Java 1.4) und habe das wohl auch recht erfolgreich verdrängt... 😞 war zu lange abwesend, weil man mich jetzt ja zu C++ zwingt.
    Sorry dafür, das sah vorhin für mich alles falsch aus. 😮

    CStoll schrieb:

    OK, das sehe ich ein - auch wenn ich die Gründe dahinter immer noch nicht richtig verstehe (bei mir zieht sich const-correctness normalerweise quer durch alle Programmteile).

    Das ist in Java ja nicht anders, Du gehst halt nur einen anderen Weg. Jetzt ein hinkender Vergleich: Chinesische Schriftzeichen kannst Du auch nicht 1:1 übersetzen, trotzdem kann man übersetzen und die können sich auch unterhalten :-))
    Es läuft aber ja darauf hinaus, daß man versucht sauber zu arbeiten, welche Mittel man dazu auch benutzt und nach dem Dialog glaube ich, daß wir beide gegenseitig Code austauschen könnten ohne einen Nervenzusammenbruch zu bekommen.



  • CStoll schrieb:

    Wozu gibt es denn in Java Generics, wenn sie dann doch wieder alles auf 'Object'-Referenzen herunterbrechen? Wenn ich einen vector<KFZ> habe, sollen da nur KFZ's reinkommen und keine Motorboote - indem du erlaubst, diesen als vector<Fahrzeug> oder vector<Object> zu betrachten, unterläufst du die Grundbedingungen (und hast plötzlich doch ein Boot oder gar einen String in dem Vector stehen, der dort nichts zu suchen hat).

    wenn du eine List<KFZ> hast darfst du da auch nur KFZs reintun und bekommst auch nur KFZs raus. du darfst auch keine List<Motorboot> and eine methode übergeben die eine List<Fahrzeug> erwartet. (gehen würde das allerdings wenn die methode eine List<? extends Fahrzeug> nimmt)

    also nur zum klarstellen 😋



  • Ja, er hatte Recht. Ich war nicht voll da.



  • java generics schrieb:

    CStoll schrieb:

    Wozu gibt es denn in Java Generics, wenn sie dann doch wieder alles auf 'Object'-Referenzen herunterbrechen? Wenn ich einen vector<KFZ> habe, sollen da nur KFZ's reinkommen und keine Motorboote - indem du erlaubst, diesen als vector<Fahrzeug> oder vector<Object> zu betrachten, unterläufst du die Grundbedingungen (und hast plötzlich doch ein Boot oder gar einen String in dem Vector stehen, der dort nichts zu suchen hat).

    wenn du eine List<KFZ> hast darfst du da auch nur KFZs reintun und bekommst auch nur KFZs raus. du darfst auch keine List<Motorboot> and eine methode übergeben die eine List<Fahrzeug> erwartet. (gehen würde das allerdings wenn die methode eine List<? extends Fahrzeug> nimmt)

    also nur zum klarstellen 😋

    Also da lag ich wohl doch richtig.

    Kann man eigentlich in Java sowas vernünftig ausdrücken:

    interface const_vector<CT>
    {
      //getter für Größe und lesenden Elementzugriff
    };
    
    class vector<T> implements const_vector< "das const-Interface zu T" >
    {
      //schreibender Elementzugriff, etc
    };
    


  • ich weiß nich genau was du meinst? aber sowas geht:

    class vector<T> implements const_vector<T>
    class vector<T> implements const_vector<? super T>
    


  • jana generics schrieb:

    ich weiß nich genau was du meinst? aber sowas geht:

    class vector<T> implements const_vector<T>
    class vector<T> implements const_vector<? super T>
    

    Das letztere sieht schon so aus, als ob es in die richtige Richtung geht (btw, schließt der Ausdruck <? super T> auch T selber mit ein?). Ich dachte eher an einen Ansatz, daß mein Datenyp irgendwo sagen kann "mein const-interface ist XYZ" (in C++ class text{typedef const_test const_interface;...} ) und daß vector<X> dann das Interface const_vector<x::const_interface> implementieren sollte).

    (btw, kann man bei Java Methodenüberschreibung auch die Parameter- und Rückgabetypen nachbessern? Sprich: gilt die 'test element(int);' in vector<test> als Definition der 'const_test element(int);' aus dem (von vector<test> implementierten) Interface const_vector<const_test>?



  • CStoll schrieb:

    Das letztere sieht schon so aus, als ob es in die richtige Richtung geht (btw, schließt der Ausdruck <? super T> auch T selber mit ein?). Ich dachte eher an einen Ansatz, daß mein Datenyp irgendwo sagen kann "mein const-interface ist XYZ" (in C++ class text{typedef const_test const_interface;...} ) und daß vector<X> dann das Interface const_vector<x::const_interface> implementieren sollte).

    meinst du sowas:
    class Vector<T extends ConstInterface> implements ConstVector<T>
    😕

    (btw, kann man bei Java Methodenüberschreibung auch die Parameter- und Rückgabetypen nachbessern? Sprich: gilt die 'test element(int);' in vector<test> als Definition der 'const_test element(int);' aus dem (von vector<test> implementierten) Interface const_vector<const_test>?

    wenn test eine unterklasse von const_test ist, oder wenn die methode als 'T element(int)' (was wohl eher sinn machen würde) ja



  • asfasfasf schrieb:

    CStoll schrieb:

    Das letztere sieht schon so aus, als ob es in die richtige Richtung geht (btw, schließt der Ausdruck <? super T> auch T selber mit ein?). Ich dachte eher an einen Ansatz, daß mein Datenyp irgendwo sagen kann "mein const-interface ist XYZ" (in C++ class text{typedef const_test const_interface;...} ) und daß vector<X> dann das Interface const_vector<x::const_interface> implementieren sollte).

    meinst du sowas:
    class Vector<T extends ConstInterface> implements ConstVector<T>
    😕

    so ähnlich - class Vector<T extends ConstInterface> implements ConstVector<ConstInterface> - wobei allerdings jedes T sein eigenes ConstInterface mitbringt (String als immutable Klasse sich selber, die 'test' von oben hat 'const_test' etc.)



  • Ich würde dir raten dich einfach an das zu halten, was die Sprache vorsieht. Java kennt (wie viele andere Sprachen auch) halt einfach keine const-correctness. Hier wurden natürlich schon viele Beispiele gebracht, die die ach so schlimmen Folgen von fehlender const-correctness zeigen, aber komischerweise musste ich noch nie in einem Programm Autos mit Farben und dergleichen nachbilden. Man muss halt einfach ein Gefühl dafür entwickeln, welche Typen man besser immutable gestaltet und dann gibt es auch keine Probleme. Zusätzlich ist es mir manchmal auch schon passiert, dass ich im Nachhinein froh darüber war, dass ich manches nicht konstant übergeben habe (gut, ich hatte natürlich kein const-correctness, aber ich habe überlegt, ob ich eine immutable Wrapper erstellen soll), weil dann doch ein sinnvoller Verwendungszweck für eine Änderung aufkam. Das ist halt ungefähr so wie mit versiegelten Klassen oder Methoden, da sie am Anfang zwar ganz nett wirken (hier: "bessere" Performance), aber man sich im Nachhinein dann doch manchmal wünscht, dass man es nicht getan hätte.



  • Edit: Naja, blödes Beispiel, außerdem könnte ConstMessage einfach kein Interface für setNewMessage() anbieten...

    ja das beispiel ist schon irgendwie blöd wenn die klasse selber schon ConstMessage heißt wär eine methode setMessage() bissl blöde

    ############################

    nein, das willst du nicht. was die klasse innerhalb ihrere methoden macht ist *ihre* sache. wenn sie es für nötig hält bei einem getFarbe() aufruf zu beschleunigen soll sie das tun. das ist eine sache der konvention und der implementierung

    ok, also getFarbe() soll das Auto Rot färben, den rückwärtsgang einlegen und dann zum Mond fliegen. Klingt plausibel.

    Und du willst wirklich erlauben, daß die Garage das gefundene Auto nebenbei zum Mond schießen darf?

    nein, deine garage wär nicht kaputt. entweder die garage verhält sich so wie sie sich verhält oder du brauchst eine neue garage.

    ############################

    Nein, die Garage verwaltet ihren eigenen Zustand (eine Sammlung von Autos). Mit geeignet gesetzten const's kann ich verhindern, daß sie dabei den internen Zustand dieser Autos beeinflussen kann. (Wenn ich selber die Garage entwickle, weiß ich, was sie tun darf. Aber ein Kollege sieht nur die Methoden der Auto-Klasse und könnte auf die Idee kommen, sie auch zu nutzen.)

    Sorry, wenn Eure Auto so geschnitten sind, dass sie eine Änderung der Farbe zulassen, dann seid Ihr selbst schuld. Wenn ich die Möglichkeiten zur Verfügung stelle, dann muss ich mich nicht wundern, wenn sie benutzt werden.

    ###########################
    Sieht soweit nicht gut aus fuer Const-Correctness.
    Koennt ihr vielleicht noch Stellung zu den Argumenten von http://c2.com/cgi/wiki?AvoidConstCompletely beziehen?

    ConstIsaVirus. Declare a pointer/reference to be const; and the TransitiveClosure? of places that pointer/reference is passed will also need to be declared const. Or else you'll need to cast away const, and that's often a bug waiting to happen.
    ConstIsaVirus is annoying when one has to make lots of edits by hand due to the ripple effect, but that nuisance is a small thing compared with the increment of correct behavior that is thereby guaranteed at compile time when used correctly, as with any kind of static type checking. Changing an int to a float is precisely as virus-like in its ripple effect.

    const promises very little. Const is not a synonym with "immutable"; all const means is "you can't change the object through this pointer/reference, and any place this pointer/reference is copied". There can be, of course, non-const pointers to the object which can mutate the object.

    The ConstQualifier's main purpose is HelpingTheCompiler; it has almost zero use in describing the user's problem.

    ###########################

    Kleines Beispiel:
    Farbe kann immutable sein, aber was wenn man ein Komplexes Objekt hat? zB getMotor().
    Wenn Motor nun Operationen hat die den Motor verändern. Beispiel: reparieren().
    Wie erlauben wir einem Client einen View auf den Motor ohne dass er rumpfuschen darf? Motor kann nicht immutable sein. In Java würde man jetzt eine defensive Kopie machen. Funktioniert auch problemlos. Meistens hat man ja immutable Objekte und wenn mal nicht, dann halt ne defensive Kopie. Tut nicht wirklich weh. Oder man verlässt sich einfach auf den Client Code - auch sehr legitim.

    In C++ hat man diese Gedankengänge aber nicht: man liefert einfach einen immutable Motor. Damit kann Auto vom Client Code verlangen: du darfst den Motor ansehen, aber nicht anfassen.

    Stimme soweit fuer die Sprache C++. Man schreibt einfach doppelt so viele Methoden in einer Klasse: Const und nicht Const. In Java hat man 2 Klassen, mutable und immutable.

    Vorteil von C++: Keine Kopien.
    Vorteil von Java: das Interface ist schlanker.
    Da man sowieso zu 90% immutable braucht, ziehe ich die Methode von Java vor.



  • dsfdfg schrieb:

    ...

    Eigentlich stimme ich da zu, ändern kann mans ja sowieso nciht so ohne weiteres, wobei ich zugebe, dass ich (so verufen das vielleicht auch bei vielen ist), z.B. das friend-Konzept manchmal gern in Java gehabt hätte. Un const ist vielleicht auch so'n Ding.



  • SammyRukka schrieb:

    das friend-Konzept manchmal gern in Java gehabt hätte.

    du willst in java die kapselung aushebeln mit methoden einer vorsinntflutlichen frickler-sprache? 😉
    besser als 'friend' wäre meiner meinung nach das: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_4_section_7.html#//apple_ref/doc/uid/TP30001163-CH7-TPXREF139



  • SammyRukka schrieb:

    dsfdfg schrieb:

    ...

    wobei ich zugebe, dass ich (so verufen das vielleicht auch bei vielen ist), z.B. das friend-Konzept manchmal gern in Java gehabt hätte.

    dafür gibts ja den package-protected modifier



  • @beide vorher:
    Ja, ich arbeite 'trotz allem' viel lieber mit Java und ja, ich kann auch ohne 'friend' gut leben und könnte mir auch ein noch eine bessere Umsetzung vorstellen, es war halt nur ein Vergleich.
    Es kommt halt ab und zu vor, dass nur bestimmte Klassen etwas an einem Objekt machen können sollen und die der package/protected sind da doch nicht immer der passende Rahmen, weil man seine Packages/Hierarchien gerade in großen Projekten auch nach anderen Kriterien aufteilt.


Anmelden zum Antworten