Vererbung & Polymorphie anhand von Beispiel erklären



  • TyRoXx schrieb:

    * In Java, denn darum geht es hier gerade.

    Sorry, hab' nur deinen Beitrag gelesen, und da du explizit "Java Schnittstellen" geschrieben hast, dachte ich es geht hier allgemein um Vererbung und nicht speziell um Java.

    TyRoXx schrieb:

    Das ist ein Vorteil. Wozu sollte eine Default-Implementierung gut sein?

    Weil man öfters Interfaces hat, wo es eine Funktion gibt die im Prinzip ausreicht, aber dann ein paar weitere die z.B. auf Geschwindigkeit optimiert sind. Bzw. sein können -- aber nicht in jeder Implementierung unbedingt optimiert werden müssen.

    Beispiel: Java's InputStream Klasse hat folgende Methoden:

    abstract int read();
    int read(byte[] b);
    int read(byte[] b, int off, int len);
    long skip(long n);
    

    Um einen (nicht optimierten) InputStream zu implementieren, muss man davon nur int read() implementieren. Die Default-Implementierung der anderen Funktionen ruft einfach wiederholt read() auf. Was in vielen Fällen gut genug ist.

    Weiters kann man so optionalen Funktionen eine Default-Implementierung mit throw new UnsupportedOperationException() verpassen.

    Natürlich könnte man das selbe auch mit Mixins machen, was vermutlich die elegantere Lösung wäre. Nur leider unterstützen Java, C#, C++ etc. keine Mixins.

    TyRoXx schrieb:

    hustbaer schrieb:

    Was auch der Grund ist warum viele Dinge in Java oder C# Klassen sind und keine Schnittstellen (z.B. Streams).

    Ich dachte immer das läge daran, dass Schnittstellen und Klassen da oft viel zu groß und möglichst eine Eierlegende sind.

    Dass das Klassen-Design der Java Standard Library nicht unbedingt das beste ist, ist klar. Gut. Was wirklich der Grund für irgendwas war kann man nachträglich oft nur mehr schwer sagen. Es sei denn man weiss zufällig warum Dinge damals so entschieden wurden.

    Sagen wir so: es ist der Grund warum man auch heute noch, in neuem Code, von Leuten die wissen was sie tun, immer noch Klassen findet, wo man eigentlich Interfaces verwenden würde. Wenn da eben nicht die Sache mit der Default-Implementierung wäre. Und es ist leicht möglich dass es der Grund, oder einer der Gründe war, dass man sowas auch in der Java Standard Library findet.



  • hustbaer schrieb:

    TyRoXx schrieb:

    Das ist ein Vorteil. Wozu sollte eine Default-Implementierung gut sein?

    Weil man öfters Interfaces hat, wo es eine Funktion gibt die im Prinzip ausreicht, aber dann ein paar weitere die z.B. auf Geschwindigkeit optimiert sind. Bzw. sein können -- aber nicht in jeder Implementierung unbedingt optimiert werden müssen.

    Vielleicht kann man das so zusammenfassen: eigentlich sollte ein Interface zwei Seiten haben, nämlich eine, die der Benutzer sieht, und eine, die der Implementierende erfüllen muß.

    Anwendungen dafür gibt es viele. Eine Standardimplementierung wie in deinem Beispiel wäre eine; eine andere das template method pattern. Oder mein Interface hat eine searchFoo() -Methode, die ich mit einer findFoo() -Methode augmentieren möchte, die eine Exception wirft, anstatt Null zurückzugeben, deren Implementierung aber natürlich generisch ist, weil sie nur searchFoo() aufruft, so daß es lästig wäre, sie jedes Mal mitimplementieren zu müssen.

    Zum Thema: ich finde die Sinnhaftigkeit von Vererbung bei vielem, was mit UI zu tun hat, einigermaßen naheliegend. Z.B. die Steuerelemente in einem Fenster; jedes hat eine Position und eine Größe oder eine Eigenschaft wie Visible oder Enabled oder eine Schriftart; und wenn ich eine Gruppe von Steuerelementen aktiviere oder deaktiviere, will ich alle gleich behandeln können. Und wenn ich einen Button haben möchte, der neben der Beschriftung eine kleine Graphik darstellen kann, ist es sinnvoll, von Button abzuleiten und nur die Zeichenroutine zu überschreiben und eine zusätzliche Eigenschaft hinzuzufügen.



  • TyRoXx schrieb:

    icarus2 schrieb:

    Natürlich gibt es die klassichen Beispiele wie z.B. die Tierwelt aber irgendwie finde ich diese doch recht künstlich.

    Es gibt kein gutes Beispiel für Vererbung, weil Vererbung kein gutes Sprachkonzept ist. Es ergibt viel zu selten Sinn.

    Falsch.



  • hustbaer schrieb:

    TyRoXx schrieb:

    Das ist ein Vorteil. Wozu sollte eine Default-Implementierung gut sein?

    Weil man öfters Interfaces hat, wo es eine Funktion gibt die im Prinzip ausreicht, aber dann ein paar weitere die z.B. auf Geschwindigkeit optimiert sind. Bzw. sein können -- aber nicht in jeder Implementierung unbedingt optimiert werden müssen.

    Das ist Premature Optimization. Und zwar die besonders eklige Sorte, weil so eine öffentliche Schnittstelle nie wieder geändert werden kann. Vielleicht fällt jemandem auf einmal eine "noch optimalere" Signatur ein. Wird dann noch eine Methode hinzugefügt? Und noch eine und noch eine?

    hustbaer schrieb:

    Beispiel: Java's InputStream Klasse hat folgende Methoden:

    abstract int read();
    int read(byte[] b);
    int read(byte[] b, int off, int len);
    long skip(long n);
    

    Um einen (nicht optimierten) InputStream zu implementieren, muss man davon nur int read() implementieren. Die Default-Implementierung der anderen Funktionen ruft einfach wiederholt read() auf. Was in vielen Fällen gut genug ist.

    Zur Not kann die JVM solche "optimierten" Methoden generieren. Macht sie nicht? Hmm, scheint sich wohl nicht zu lohnen. Dann lohnt sich das erst recht nicht für Menschen, die sich ewig mit redundanten Schnittstellen herumschlagen müssen.

    So hätte ich InputStream und so entworfen:

    public class InputStreamExamples {
    
    	public static void main(String[] args) {
    		InputStream s = new GeneratorInputStream(new ByteGenerator() {
    
    			@Override
    			public int read() {
    				return (int) '!';
    			}
    		});
    		byte[] b = new byte[2];
    		int r = s.read(b);
    		assert (r == b.length);
    		assert (b[0] == '!');
    		assert (b[1] == '!');
    	}
    }
    
    public interface ByteGenerator {
    	int read();
    }
    
    public interface InputStream {
    	int read(byte[] b);
    	//...
    }
    
    public class GeneratorInputStream implements InputStream {
    
    	private final ByteGenerator next;
    
    	public GeneratorInputStream(ByteGenerator next) {
    		this.next = next;
    	}
    
    	@Override
    	public int read(byte[] b) {
    		int r = 0;
    		for (; r < b.length; ) {
    			int element = next.read();
    			if (element < 0) {
    				break;
    			}
    			b[r] = (byte)element;
    			++r;
    		}
    		return r;
    	}
    }
    

    hustbaer schrieb:

    Weiters kann man so optionalen Funktionen eine Default-Implementierung mit throw new UnsupportedOperationException() verpassen.

    .. was eine ganz schlechte Idee ist. Wenn Schnittstellen anfangen zu lügen, kann man sich die auch gleich sparen.



  • TyRoXx schrieb:

    hustbaer schrieb:

    TyRoXx schrieb:

    Das ist ein Vorteil. Wozu sollte eine Default-Implementierung gut sein?

    Weil man öfters Interfaces hat, wo es eine Funktion gibt die im Prinzip ausreicht, aber dann ein paar weitere die z.B. auf Geschwindigkeit optimiert sind. Bzw. sein können -- aber nicht in jeder Implementierung unbedingt optimiert werden müssen.

    Das ist Premature Optimization. Und zwar die besonders eklige Sorte, weil so eine öffentliche Schnittstelle nie wieder geändert werden kann. Vielleicht fällt jemandem auf einmal eine "noch optimalere" Signatur ein. Wird dann noch eine Methode hinzugefügt? Und noch eine und noch eine?

    🙄
    Nein, es ist nicht premature, es ist bitter nötig. Leute wie du sind der Grund warum so viele Programm so unnötigerweise so langsam sind.
    Kannst du noch mehr als Phrasen dreschen?

    TyRoXx schrieb:

    hustbaer schrieb:

    Beispiel: Java's InputStream Klasse hat folgende Methoden:

    abstract int read();
    int read(byte[] b);
    int read(byte[] b, int off, int len);
    long skip(long n);
    

    Um einen (nicht optimierten) InputStream zu implementieren, muss man davon nur int read() implementieren. Die Default-Implementierung der anderen Funktionen ruft einfach wiederholt read() auf. Was in vielen Fällen gut genug ist.

    Zur Not kann die JVM solche "optimierten" Methoden generieren. Macht sie nicht? Hmm, scheint sich wohl nicht zu lohnen. Dann lohnt sich das erst recht nicht für Menschen, die sich ewig mit redundanten Schnittstellen herumschlagen müssen.

    Geh mal zum Aldi und hol dir ne Buddel Realität. Oder besser ne ganze Kiste.
    Nein, die JVM kann das nicht. Und sie könnte es auch nicht können.
    Boah.

    TyRoXx schrieb:

    So hätte ich InputStream und so entworfen:
    (...)

    Ja so stellt sich klein TyRoXx das vor.
    Probier' es doch einfach aus. Mach nen FileInputStream auf ein mittelgrosses File, sagen wir ein paar hundert MB.
    Und dann lies es 1x mit read(), und 1x mit read(byte[]) mit nem sagen-wir-mal 1MB grossen Array.
    Dann siehst du was Sache ist.

    TyRoXx schrieb:

    hustbaer schrieb:

    Weiters kann man so optionalen Funktionen eine Default-Implementierung mit throw new UnsupportedOperationException() verpassen.

    .. was eine ganz schlechte Idee ist. Wenn Schnittstellen anfangen zu lügen, kann man sich die auch gleich sparen.

    Siehe oben: ne Buddel Realität.

    -----

    In Summe: Wenn man keine Ahnung hat, einfach mal die Fresse halten!



  • EDIT: Ich weiß gerade gar nicht was dein Problem ist. Man muss bei meinem Ansatz ja nicht den ByteGenerator benutzen, wenn es schnell sein soll.

    Ich wollte nur zeigen, dass es nicht nötig ist zwei Schnittstellen zu einer zu verschmelzen. Und wenn man die Schnittstellen nicht unnötig groß macht, braucht man auf einmal keine Default-Implementierung für irgendwas mehr.

    Das Verschmelzen zweier Schnittstellen ist die von mir gemeinte Premature Optimization. Nicht das Lesen in Arrays.



  • TyRoXx schrieb:

    EDIT: Ich weiß gerade gar nicht was dein Problem ist. Man muss bei meinem Ansatz ja nicht den ByteGenerator benutzen, wenn es schnell sein soll.

    Ich wollte nur zeigen, dass es nicht nötig ist zwei Schnittstellen zu einer zu verschmelzen. Und wenn man die Schnittstellen nicht unnötig groß macht, braucht man auf einmal keine Default-Implementierung für irgendwas mehr.

    Das Verschmelzen zweier Schnittstellen ist die von mir gemeinte Premature Optimization. Nicht das Lesen in Arrays.

    Ergibt das überhaupt Sinn, wenn Du (wie Du selber sagst) Vererbung nirgends sinnvoll anwenden kannst, über Schittstellendesign zu referieren?





  • KennerDesJava8 schrieb:

    Kennt ihr eigentlich schon Java 8?
    http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

    Nö, kannte ich nicht!
    Cool, danke!



  • volkard schrieb:

    Ergibt das überhaupt Sinn, wenn Du (wie Du selber sagst) Vererbung nirgends sinnvoll anwenden kannst, über Schittstellendesign zu referieren?

    Entschuldige bitte meine Undeutlichkeit. Ich möchte nur von Implementierungsvererbung abraten. Schnittstellenvererbung hingegen ist sehr wichtig.

    Für Implementierungsvererbung sehe ich keine sinnvolle Anwendung.
    In C++ gibt es da noch reine Implementierungsvererbung, also private Vererbung. Das ist etwas ganz anderes, weil keine öffentliche Methode überschrieben wird, und deswegen in Ordnung.



  • icarus2 schrieb:

    Angenommen ihr müsstet einer Gruppe von ca. 30 Studenten innerhalb von 45 Minuten Vererbung und Polymorphie erklären: Welches Beispiel würdet ihr dafür verwenden?

    Ich verwende in der Regel eine Klasse, die Strings verschlüsselt: Es gibt eine Basisklasse Encrypter mit virtuellen Funktionen encrypt und decrypt, davon leite ich Atbash (a<->z, b<->y...) und Caesar ab. Allerdings bringe ich den Leuten C++ praktisch bei. Das heißt, die programmieren das anschließend. Das ist mit 45 Minuten etwas zu knapp.

    Die Tierwelt finde ich für kleine Beispiele gut, nutze das Beispiel auch. Wenn viel Zeit ist, es also um ein Test-Projekt geht, halte ich die Shapes am besten, wenn Zeit genug ist, diese auch zu zeichnen.

    Ansonsten gefällt mir das beispiel im GoF-Entwicklungsmuster, wo ein Editor besprochen wird, der Zeilen aus einzelnen Zeichen zusammensetzt, die Grafiken oder Zeichen sein können, die ihre Größe auf dem Bildschirm zurückliefern und sich zeichnen lassen können.

    Kannst Du aber alles vergessen: In 45 Minuten würde ich schätzen, dass Du vielleicht 5 das verständlich machen kannst und die vergessen es bis zum Abend wieder. Von daher ist es relativ egal, was Du erzählst, die Zeit reicht nicht, um etwas sinnvoll zu vermitteln.

    cloidnerux schrieb:

    Vererbung und Polymorphie wurden innerhalb von zwei Vorlesungsstunden (2 Mal 45 Minuten) eingeführt. Sie sollte also schon einmal davon gehört aber wohl kaum richtig verstanden haben, da es sehr schnell ging (und jetzt muss ich das innerhalb von 45 Minuten richten 🙂 ).

    Ich habe die Erfahrung gemacht, dass man bei Studenten im 3. Semester quasi bei 0 anfängt, obwohl die schon 2 Semester Vorlesungen hatten. Gerade bei Java sind die Vorstellungen teils sehr... virtuell.
    Ich erkläre Vererbung und Polymorphie daher an der tatsächlichen Umsetzung: Ich erkläre eine Struktur, dass die Daten bei Vererbung hintereinander geschrieben werden, dass eine Methode auch nur eine Funktion mit this-Pointer ist und dass man über Funktionzeiger, bzw. die vtable an die Funktionszeiger kommt.
    Das ist eher imperative Herangehensweise, aber OOP ist auch nur ein imperatives Design-Pattern. Wenn man OOP die Magic nimmt, wird es leichter begreifbar.

    Das klappt eigentlich sehr gut, jedenfalls schließe ich das aus Aussagen wie "Jetzt habe ich verstanden, was ich die letzten zwei Semester eigentlich getan habe".

    Unter Berücksichtigung, dass sie das eigentlich ja schonmal gehört haben, würde ich schätzen, dass Du hier den Leuten am ehesten etwas Nützliches mitgeben kannst, weil sie eigentlich Bekanntes aufgreifen müssen und zusätzliche Informationen erhalten.

    Benutze eine Tafel, keine Präsentation, stelle richtungsführende Fragen und lass die Studenten das entwickeln. Wenn Du denen nur was von Rechtecken erzählst, musst Du die Hälfte danach wecken. Setz Dir sinnvolle Ziele für 45 Minuten Show und akzeptiere, dass Du in 45 Minuten mit einem kleinen Schritt weiter kommst, als wenn Du einen großen Versuchst und nur Verwirrung stiftest.



  • Xin schrieb:

    icarus2 schrieb:

    Angenommen ihr müsstet einer Gruppe von ca. 30 Studenten innerhalb von 45 Minuten Vererbung und Polymorphie erklären: Welches Beispiel würdet ihr dafür verwenden?

    Ich verwende in der Regel eine Klasse, die Strings verschlüsselt: Es gibt eine Basisklasse Encrypter mit virtuellen Funktionen encrypt und decrypt, davon leite ich Atbash (a<->z, b<->y...) und Caesar ab.

    Warum hat die Klasse Encrypter eine Methode decrypt ? Das ist ein Widerspruch.
    Warum hat Encrypter überhaupt Methoden für beide Richtungen? Man benötigt doch an einer Code-Stelle so gut wie immer nur eine der beiden Richtungen. Die Schnittstelle ist also unnötig groß.
    Und lass mich raten: Die beiden Methoden sind bei Caesar fast identisch. An einer Stelle steht so etwas wie 26-n wo in der anderen Methode nur n steht.

    Xin schrieb:

    Ich erkläre Vererbung und Polymorphie daher an der tatsächlichen Umsetzung: Ich erkläre eine Struktur, dass die Daten bei Vererbung hintereinander geschrieben werden, dass eine Methode auch nur eine Funktion mit this-Pointer ist und dass man über Funktionzeiger, bzw. die vtable an die Funktionszeiger kommt.
    Das ist eher imperative Herangehensweise, aber OOP ist auch nur ein imperatives Design-Pattern. Wenn man OOP die Magic nimmt, wird es leichter begreifbar.

    👍



  • TyRoXx schrieb:

    Warum hat Encrypter überhaupt Methoden für beide Richtungen?

    Ich habe sie jetzt einfach mal Encrypter genannt, weil ich den Namen der Basisklasse jetzt auch nicht wirklich vorschreibe. Es kann auch CryptBase oder was auch immer sein.

    TyRoXx schrieb:

    Man benötigt doch an einer Code-Stelle so gut wie immer nur eine der beiden Richtungen. Die Schnittstelle ist also unnötig groß.
    Und lass mich raten: Die beiden Methoden sind bei Caesar fast identisch. An einer Stelle steht so etwas wie 26-n wo in der anderen Methode nur n steht.

    Es geht mir hier darum, ein Beispiel für Vererbung und virtuelle Funktionen zu präsentieren. Ein Übungsbeispiel. Und "Ein" steht für 1.

    Und Caesar und Atbash sind leicht zu implementieren, weil es zwar durchaus eine Programmier-Übung sein soll, aber eben kein Programmier-Projekt.

    TyRoXx schrieb:

    Xin schrieb:

    Das ist eher imperative Herangehensweise, aber OOP ist auch nur ein imperatives Design-Pattern. Wenn man OOP die Magic nimmt, wird es leichter begreifbar.

    👍

    !?
    Erstaunlich... dass das mal einer gut findet. ^^

    In der Regel bekomme ich von den "Experten" dafür einen auf den Deckel, weil OOP ja nicht mit Funktionen arbeitet sondern mit "Messages" und das ganze ja abstrahiert (eben so, dass es keiner kapiert) und man das deswegen auch nich so konkret beschreiben darf.

    Dafür kapieren die Studenten, was sie tun. 🙂



  • Xin schrieb:

    TyRoXx schrieb:

    Xin schrieb:

    Das ist eher imperative Herangehensweise, aber OOP ist auch nur ein imperatives Design-Pattern. Wenn man OOP die Magic nimmt, wird es leichter begreifbar.

    👍

    !?
    Erstaunlich... dass das mal einer gut findet. ^^

    Find ich auch gut.
    👍



  • TyRoXx schrieb:

    Xin schrieb:

    icarus2 schrieb:

    Angenommen ihr müsstet einer Gruppe von ca. 30 Studenten innerhalb von 45 Minuten Vererbung und Polymorphie erklären: Welches Beispiel würdet ihr dafür verwenden?

    Ich verwende in der Regel eine Klasse, die Strings verschlüsselt: Es gibt eine Basisklasse Encrypter mit virtuellen Funktionen encrypt und decrypt, davon leite ich Atbash (a<->z, b<->y...) und Caesar ab.

    Warum hat die Klasse Encrypter eine Methode decrypt ? Das ist ein Widerspruch.
    Warum hat Encrypter überhaupt Methoden für beide Richtungen? Man benötigt doch an einer Code-Stelle so gut wie immer nur eine der beiden Richtungen. Die Schnittstelle ist also unnötig groß.
    Und lass mich raten: Die beiden Methoden sind bei Caesar fast identisch. An einer Stelle steht so etwas wie 26-n wo in der anderen Methode nur n steht.

    Wie das mit Schnittstellen in C++ aussieht weiß ich nicht. Aber in Java brauchst du Schnittstellen z.B. wenn dir egal ist was für ein Objekt du bekommst, solange es etwas Bestimmtes kann. Entsprechend beschreibt eine Schnittstelle nicht welche Methoden eine implementierende Klasse braucht, sondern welche Methoden von der empfangenden Klasse benötigt werden.
    Braucht eine empfangende Klasse also sowohl encryption als auch decryption, muss die Schnittstelle beide vorweisen. Gut wäre also vllt wenn CryptBase von zwei Schnittstellen (encryption und decryption) „erbt“.



  • Xin schrieb:

    TyRoXx schrieb:

    Xin schrieb:

    Das ist eher imperative Herangehensweise, aber OOP ist auch nur ein imperatives Design-Pattern. Wenn man OOP die Magic nimmt, wird es leichter begreifbar.

    👍

    !?
    Erstaunlich... dass das mal einer gut findet. ^^

    In der Regel bekomme ich von den "Experten" dafür einen auf den Deckel, weil OOP ja nicht mit Funktionen arbeitet sondern mit "Messages" und das ganze ja abstrahiert (eben so, dass es keiner kapiert) und man das deswegen auch nich so konkret beschreiben darf.

    Ich muss meine Zustimmung leider ein wenig einschränken: Laut Wikipedia sind funktionale Sprachen "immer" (?) deklarativ und nicht imperativ. OOP findet man auch in deklarativen Sprachen. Das Lambda-Kalkül zum Beispiel ist pure OOP und das ohne Vererbung :).

    In C ist OOP aber ein Entwurfsmuster. So kann man dann auch die übliche Umsetzung von Methoden und virtual im C++-Compiler illustrieren.



  • Theoretisches Glaubensbekenntnis ohne Wert für den Fragestellenden

    TyRoXx schrieb:

    Ich muss meine Zustimmung leider ein wenig einschränken: Laut Wikipedia sind funktionale Sprachen "immer" (?) deklarativ und nicht imperativ. OOP findet man auch in deklarativen Sprachen. Das Lambda-Kalkül zum Beispiel ist pure OOP und das ohne Vererbung :).

    Ich glaube, hier muss man sich zum einen Fragen, was eigentlich ein Objekt ist und was Objektorientiert ist, ist gerne auch eine Glaubensfrage.

    Dass funktionale Sprachen immer nicht imperativ sind, halte ich für ein Gerücht. Dass das switch()/if-Konstrukt nicht vom Entwickler geschrieben wird, bedeutet nicht, dass es nicht da ist. In FP nutzt man mehr Rekursion und entsprechend sind FPLs optimiert einen Rekursionsanker oder andere Besonderheiten zu formulieren.

    Das ist auch nicht gerade die Variante von OOP, die man in C++, Java oder C# als OOP bezeichnet würde. Es ist die alte Variante, wie man in C vereinfacht OOP abbildet - was heute mit C++ für OOP eher verpönt wird: Man möge doch bitte ableiten, statt die richtige Funktion an einem anderen Status des Objektes als des Datentyps zu wählen.

    Man kann in C genauso gut funktional programmieren. Man tut es teilweise auch. Man nennt es hier lediglich nicht so. Und man ist nicht darauf beschränkt, was bedeutet, dass man mit den Garantien zurückhaltender sein muss.

    **Das alles ist aber nicht das Problem des Threadstarters, der das Verständnis von OOP in Java erweitern soll.
    **

    TyRoXx schrieb:

    In C ist OOP aber ein Entwurfsmuster. So kann man dann auch die übliche Umsetzung von Methoden und virtual im C++-Compiler illustrieren.

    Und Java und C++ sind keine imperative Programmiersprachen, die Unterstützung für rekursive Algorithmen bieten, sondern imperative Sprachen, die Unterstützung für das Datentyp-Orientierte Programmierung anbietet. Ich vermeide das Wort "Objektorientiert" hier mal, weil sich OOP eigentlich nicht um das Objekt kümmert, sondern nur um den Datentyp des Objektes. Bei echter OOP müsste man in meinem Verständnis die vtable pro Objekt manipulieren können.
    Aber das würde nun wirklich einen Glaubenskrieg beschwören. Wichtig ist nur, was Java kann und was die Leute verstehen sollten.



  • Wiki schrieb:

    Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft.

    Ich weiß nicht was man dem hinzufügen soll. Wieso hat das was mit "imperativ" zu tun? Das passiert bei Java / C# sofern es eine "Wirklichkeit" gibt. Die einzelnen Objekte komunizieren mit einander und die Eigenschaften / Aktionen (methoden) werden intern "imperative" gestaltet. Ich verstehe den Konflikt nicht.
    Wenn ich wirklich auf dem Schlauch stehe kann mir das vllt jemand erklären?



  • Zur Information: Sqwan zitiert Wikipedia zum Begriff "Objektorientierte Programmierung".

    Sqwan schrieb:

    Wiki schrieb:

    Die Grundidee besteht darin, die Architektur einer Software an den Grundstrukturen desjenigen Bereichs der Wirklichkeit auszurichten, der die gegebene Anwendung betrifft.

    Ich weiß nicht was man dem hinzufügen soll. Wieso hat das was mit "imperativ" zu tun? Das passiert bei Java / C# sofern es eine "Wirklichkeit" gibt. Die einzelnen Objekte komunizieren mit einander und die Eigenschaften / Aktionen (methoden) werden intern "imperative" gestaltet. Ich verstehe den Konflikt nicht.
    Wenn ich wirklich auf dem Schlauch stehe kann mir das vllt jemand erklären?

    Dem gibt es nichts hinzuzufügen. Es gibt auch keinen Konflikt in der Programmierung.
    Der Punkt ist nämlich, dass das Zitat der imperativen Programmierung auch nichts hinzufügt. Das ist wiederum eine Glaubensfrage und ich gehöre halt dem Glauben an, dass sich nichts an der Wirklichkeit ändert, egal ob man this->method( 1, 2, 3 ) schreibt oder function( this, 1, 2, 3 ).
    Wichtig ist nur, ob function sich abhängig von this verhält - wie das implementiert wird oder wir man das im Quelltext formuliert, spielt für die Wirklichkeit keine Rolle.
    Genau deswegen wurde der imperativen Programmierung auch nichts hinzugefügt.
    Manche glauben aber, dass auto.oeffneTuer() intuitiver wäre als oeffneTuer(auto);



  • Xin schrieb:

    Dass funktionale Sprachen immer nicht imperativ sind, halte ich für ein Gerücht. Dass das switch()/if-Konstrukt nicht vom Entwickler geschrieben wird, bedeutet nicht, dass es nicht da ist. In FP nutzt man mehr Rekursion und entsprechend sind FPLs optimiert einen Rekursionsanker oder andere Besonderheiten zu formulieren.

    Ich halte die Unterscheidung zwischen imperativ und deklarativ für ungeschickt. Das war vielleicht vor 40 Jahren mal praktisch. Da nannte man Sprachen, die Statement für Statement nach Assembly übersetzt wurden, imperativ. Und Sprachen, die so langsam sein konnten, wie sie wollten, Hauptsache schön mathematisch, nannte man deklarativ. Heute ist diese Unterscheidung wenig nützlich, weil sich die meisten Sprachen irgendwo zwischen diesen Extremen bewegen. In modernem C++ beschreibt man zunehmend was man will und weniger wie. In SQL, das angeblich deklarativ ist, achtet man in Wirklichkeit ständig auf das wie, wenn man Anfragen auf Geschwindigkeit optimiert.

    Xin schrieb:

    Ich vermeide das Wort "Objektorientiert" hier mal, weil sich OOP eigentlich nicht um das Objekt kümmert, sondern nur um den Datentyp des Objektes. Bei echter OOP müsste man in meinem Verständnis die vtable pro Objekt manipulieren können.

    In OOP geht es nur um Objekte. Es geht nicht um Klassen und nicht um vtables.
    OOP geht schließlich wunderbar ohne Klassen.
    Was bei Wikipedia über OOP steht, ist in dem Punkt widersprüchlich:

    http://de.wikipedia.org/wiki/Objektorientierte_Programmierung schrieb:

    Es enthält Informationen über die auftretenden Objekte und deren Abstraktionen, ihre Typen. Die Umsetzung dieser Denkweise erfordert die Einführung verschiedener Konzepte, insbesondere Klassen, Vererbung, Polymorphie und spätes Binden.

    Tatsächlich braucht man keine Klassen, keine Vererbung und keine Polymorphie. Nur spätes Binden braucht man. Genau das kann das Lambda-Kalkül und so ziemlich jede andere sinnvolle Programmiersprache.

    Später im Artikel steht dann der Widerspruch:

    http://de.wikipedia.org/wiki/Objektorientierte_Programmierung schrieb:

    Die ISO-Definition gilt inzwischen im Allgemeinen als zu vereinfachend, da auch klassenlose objektorientierte Sprachen existieren und auch der Vererbung inzwischen weniger Bedeutung beigemessen wird als noch in den 1990ern.


Anmelden zum Antworten