Da hat sich jemand viel Mühe gegeben, seine Meinung zu begründen:
Object Oriented Programming is an expensive disaster which must end | Smash Company
Was meint ihr?
Da hat sich jemand viel Mühe gegeben, seine Meinung zu begründen:
Object Oriented Programming is an expensive disaster which must end | Smash Company
Was meint ihr?
habs gelesen und die Antwort ist einfach: der Autor irrt
ne, ist ja gar nicht zu schaffen, schon irgendwas handfestes herausgelesen?
wird Alternative genannt, mehr funktionial wie Scala?
Code für einzelne Probleme?
Es gibt schon ein paar Clojure-Schnipsel und so. Der Autor scheint es lispig zu mögen. Haskell wird zwar erwähnt, aber nicht vorgeführt.
The worst accusation I can make about OOP encapsulation is that it fails to give us the protection from unwanted change that it promises us. Consider this classic example:
class UniqueId {
private i = 0;
function getUniqueId() {
return i++;
}
}Let us assume that multiple threads are doing some work, perhaps resizing images, and to ensure a unique name for each image, they want a function that will return a unique number that they can use as part of the name. The var i is “encapsulated” because we have declared it to be private — the only way to access it is using the accessor function getUniqueId(). But sadly, it turns out that this is not an atomic operation:
i++
Klar ist das ein Problem, aber eines das in der Implementierung der JVM liegt, nicht in der OOP als solcher.
I want to worry about brittle base classes and tight-coupling between the interface and the implementation.
Da scheint der Gute was falsch verstanden zu haben und macht daraus ein Problem der OOP.
Der Tenor ist wohl: OOP-Programmierer sind in ihrere Welt gefangen und zu blöd die Vorteile der neuen Funktionalen Sprachen zu erkennen.
Ich habe mich mit „seiner Lieblingssprache“ Clojure beschäftigt und muss sagen: Ja, ich bin zu blöd die Vorteile zu erkennen.
Ja, Java ist langathmig und erfordert einigen „Boilerplate code“.
Aber den ziehe ich gern den millionen Klammern in Clojure vor…
weiter werde ich mir dass nicht antun.
bye
TT
Moin,
tl;dr
Ist das sein Fazit?
Meine Meinung: OOP mit Java. Immer. (Fast.)
Viele Grüße
Fancy
But don’t ever use OOP. OOP does not have any unique strengths.
ein Wunder dass er (automatisch immer ein Mann angenommen…) überhaupt English spricht,
denn sowas wie Verbreitung sind typischerweise Eigenschaften, die in solchen Betrachtungen keinen Wert haben,
konsequent müsste er finnisch oder sächsisch oder ubuntu sprechen
nach optimaler Hammingdistanz der wichtigsten Wörter oder aufgeräumter Grammatik
Dürfte ich freundlichst Fragen, wie lange du schon mit Java programmierst?
Und wie lange hast du dich mit clojure beschäftigt?
Und hast du die Klammern gezählt?
Ein Typisches Clojure-Programm hat weniger Klammern als ein Java Programm, welches den selben Zweck erfüllt.
Der Unterschied ist, dass es vorkommen kann, dass sich die schließenden Klammern am Ende einer Funktion aufsummieren.
Dies mag den anschein erwecken, dass es so viele Klammern sind, weil viele es nicht gewohnt sind drei oder vier schließende Klammern hintereinander zu sehen)))).
Aber das lässt mich vermuten, dass du dich nur Oberflächlich damit beschäftigt hast. Ansonsten wäre dir z.B. dieses „->“ oder dieses „->>“ Macro schon untergekommen.
Kleines Beispiel aus einer Clojure-Repl
[Clojure]> (+ 1 (+ 2 (+ 3 4)))
10
(-> 1 (+ 2) (+ 3) (+ 4))
10
(+ 1 2 3 4)
10
[/Clojure]
6 Klammern, 3 Klammern am Stück.
8 Klammern, 2 Klammern am Stück.
2 Klammern.
Und in objektorientiert Java
BigInteger.valueOf(1).add(BigInteger.valueOf(2)).add(BigInteger.valueOf(3)).add(BigInteger.valueOf(4))
14 Klammern!!! (als Ausrufezeichen mal visualisiert) Aber es verteilt sich besser auf dem Screen. Man muss schon scrollen, wenn man alle Klammern mal gesehen haben will.
Ich mag Java. Keine Frage, aber der leicht angestaubte Java-Code mit dem ich mich gerade rumschlagen muss und der gerne mal das ein oder andere Refactoring vertragen würde lässt mich sehnsüchtig in Erinnerung an so manchen Clojure-Code schwelgen.
Dann schau ich mal was der Schreibende von sich gegeben hat.
So ganz unrecht hat er mit dieser Aussage aber nicht, eine Entkopplung von Interface und Implementation (wie Typklassen in Haskell) hat **wirklich **viele Vorteile. Ich sehe nur nicht, warum solche Konzepte nicht mit OOP vereinbar sein sollen, siehe z.B. implicit conversions in Scala.
Also für mich lässt sich das ganze so zusammen fassen: OOP wie ich es aus den Sprachen kenne führt zu syntaktischen Konstrukten die länger sind als die Konstrukte in FP-Sprachen.
Das ist völlig richtig. Nur ist es ein Trugschluss deshalb zu meinen der Code wird dadurch wartbarer. Also wirklich FP programmiert habe ich nur mit Haskell und da sind mir Snippets begegnet die insgesamt 20 Zeichen nicht überschritten haben und ich bin (ungelogen!) zwei Stunden da gesessen bis ich das eine Funktional verstanden habe. HOF sind praktisch wenn man weiß was man macht, allerdings sind sie auch schuld, dass Code schwer lesbarer wird. Abgesehen davon, dass FP-Code sehr messy wird sobald man die äußere Welt anpatzen möchte. Z.B. ergibt DB-Zugriff und Haskell scheußlichen Code. Das lässt sich allerdings schön in OOP ala Java abbilden.
Es ist wirklich nicht alles Gold was glänzt. Aber auch nicht alles Scheiße was bereits ein wenig abgenützt ist …
[quote=Landei]So ganz unrecht hat er mit dieser Aussage aber nicht, eine Entkopplung von Interface und Implementation (wie Typklassen in Haskell) hat wirklich viele Vorteile.[/quote]Nunja, Haskell kenne ich ur dem Namen nach aber ich Verstehe wirlklich nicht, in wie fern Java-Interfaces mit dem Implementierungen gekoppelt sind und wo Das Konzept von Java nachteile hat (die nicht in der starken Typisierung liegen).
bye
TT
[QUOTE=Timothy_Truckle;107182]Nunja, Haskell kenne ich ur dem Namen nach aber ich Verstehe wirlklich nicht, in wie fern Java-Interfaces mit dem Implementierungen gekoppelt sind und wo Das Konzept von Java nachteile hat (die nicht in der starken Typisierung liegen).
bye
TT[/QUOTE]
Ein Haskell-Beispiel: Du hast irgendwoher ein Modul mit Datums-Funktionen, die auf einem Typ Date
arbeiten. Dummerweise musst du jetzt zwei Dates vergleichen. In Java funktioniert das nur, wenn der Entwickler von Date
mitgedacht und equals()
ordentlich überschrieben hat. In Haskell gibt es die Typklasse Eq, die im Prinzip nicht mehr als eine Art “Interface” um eine equals-artige Funktion ==
ist. Der Witz ist, dass man für Date
jetzt nachträglich und unabhängig vom bestehenden Code eine Instanz für Eq
schreiben kann - völlig entkoppelt, aber trotzdem typsicher.
Danach kann man Date
in Funktionen benutzen, die Eq
voraussetzen, z.B. elem :: Eq a => a -> [a] -> Bool
, in Java-Schreibweise <T extends Eq<T>> boolean elem(T t, List<T> list)
(also ungefähr List.contains()
). Und Eq
ist nur ein ganz einfaches Beispiel, Typklassen können sehr komplex werden und auch aufeinander aufbauen (z.B. gibt es für Vergleiche die Typklasse Ord
, die Eq
sozusagen “erweitert”)
Also ich finde Haskell auch sehr schön und elegant, weil die Sprache „einfach“ und „mathematisch“ ist, viele elegante Programme erlaubt und sehr sparsam ist.
Möchte aber mal auf eine simple Tatsache hinweisen: Das bedeutet in der Praxis gar nichts.
Würde man in Haskell eine komplexe GUI mit SQL-Datenbank-Anbindung, Im- und Export in Office in verschiedenen Lokalisierungen, Zeitzonen und Netzwerkprotokollen schreiben, dann sähe es anders aus. Da man das bisher gar nicht machen kann, gibt es nur wenig Grund zur Hoffnung, dass dann dort alles ebenso schön und elegant wäre - die ganze Illusion der Einfachheit und der kürzeren Syntax kommt einzig nur daher, dass immer nur kleine, ausgewählte Beispiele vorgestellt und diskutiert werden.
Und was die Lesbarkeit betrifft: man braucht in Haskell und den FP Sprachen NOCH LÄNGER als in Java, bis man Quelltexte auf Anhieb halbwegs versteht - und in Java dauert das schon ziemlich lange.
Sagt eigentlich schon alles (PHP? für ein CRON-Skript??). Völlig hirnverbrannt. Natürlich nimmt man für ein (Wegwerf-)Skript immer die Programmiersprache, die man am besten kann - mit der man am schnellsten zum Ziel kommt. Natürlich lässt man seinen Leopard Kampfpanzer in der Garage, wenn man sich eine Kiste Bier holt, das ist doch kein Argument.
Jeder weiß, dass am Anfang - bei kleinen Beispielprojekten - OOP bzw. Java viel Boilerplate-Code erfordert und etwas umständlich ist. Die Vorteile von OOP liegen bei etwas größeren Projekten (dafür wurde der Quatsch ja auch erfunden).
Was ich immer toll finde, sind die Verweise auf „kurze Fragmente“, mit denen sich diese oder jene Aufgabe mit weniger Zeichen realisieren lassen. Völlig absurd, diese vergleiche. In meiner eigenen Programmiersprache (genannt SUFF) kann man übrigens eine html-Datei holen, daraus die erste
extrahieren und in Excel exportieren mit dem Befehl
holeHTMLundExtrahiereExcel(**URL**, **Filename**)
der Hammer, oder?
[ot]Eine gewisse Parallele zu Guns at home more likely to be used stupidly than in self-defense | Ars Technica könnte man unterstellen, aber … vielleicht lese ich es bei Gelegenheit mal wirklich ;)[/ot]
Ich habe noch ein wenig über die Kritikpunkte nachgedacht. Eines der Hauptprobleme von OOP scheint die zu enge Kopplung von Interface, Implementierung und Typ zu sein. Ich glaube aber, dass sich das relativ “leicht” reparieren ließe.
Eine tolle Sache in Haskell ist newtype, das aus einem bestehen Typ einen neuen, nicht austauschbaren macht. Damit kann ich z.B. aus einem Double ohne irgendwelche Handstände (oder Performanceverluste) ein Meter machen. Double-Methoden nehmen keine Meter, Meter-Methoden nehmen keine Double - Marskrater ausgeschlossen. Das wäre ein Beispiel dafür, den Typ von der Implementierung unabhängig zu machen.
Man kann diese Idee um Vererbung erweitern: Dabei wird nur die Implementierung übernommen, und einen eigenständigen, mit dem Ausgangstyp nicht irgendwie assoziierten Typ. Das wäre überall da nützlich, wo eine Vererbung das LSP verletzt (etwa java.util.Properties).
Typklassenartige Strukturen gibt es schon in OOP (Scalas Implicits), und sie arbeiten - bei vernünftigen Einsatz - recht gut. Ebenso Typ-Aliase (wie in Scala oder C++).
Bzgl Haskell xkcd: Haskell
nebenbei: das Typsystem von Scala ist eine abartige eierlegende Wollmichdrecksau - verglichen damit sind Java Generics ein Traum an Klarheit und Übersichtlichkeit. Und die implicits von Scala werden - sollte das jemals eine weitere Verbreitung finden - irgendwann einmal ein Atomkraftwerk** implicit **explodieren lassen
Man muss nicht alles machen. Nicht jeder Luxus ist gut.
[QUOTE=Bleiglanz]nebenbei: das Typsystem von Scala ist eine abartige eierlegende Wollmichdrecksau - verglichen damit sind Java Generics ein Traum an Klarheit und Übersichtlichkeit. Und die implicits von Scala werden - sollte das jemals eine weitere Verbreitung finden - irgendwann einmal ein Atomkraftwerk** implicit **explodieren lassen
Man muss nicht alles machen. Nicht jeder Luxus ist gut.[/QUOTE]
Keine Frage, in Scala ist viel “Gewachsenes” dabei, ohne dass eine entsprechende typtheoretische Basis dahinterstand, was zu nicht-orthogonalen Verhalten führt. Allerdings geht man mit dem Problem offen um, und arbeitet intensiv an einer “sauberen” Version: https://github.com/lampepfl/dotty
Ohne jetzt wieder Flamewars zu starten mal eine kurze Tour durch Scalas Typsystem:
Strukturelle Typen (“hier kommt ein beliebiger Typ, der eine Methode mit folgender Signatur hat”). Meiner Meinung nach nicht unbedingt eine schlechte Idee, aber schlecht mit anderen Features zu kombinieren. Selten wirklich benötigt, sollte weggelassen werden.
Pfadabhängige Typen: schwer zu verstehen, selten benötigt. Bin eher für weglassen, wenn keine Vereinfachung möglich ist
Typ-Aliases (“Mit ‘Dictionary’ meine ich Map<String, String>”). Nützlich, kaum problematisch. Macht einfach nur komplizierte Signaturen lesbarer oder gibt die “Funktion” (etwa “City” statt “String”) wieder.
Generische Typen wie in Java: Nützlich, wenn man sie nicht überstrapaziert
Selbst-Typ Ungeheuer nützliches Konzept, kann in Java nur unzureichend mit dem CRTP (wie etwa in der Enum-Klasse) simuliert werden.
Definitionsseitige Varianzen (damit kann z.B. ausgedrückt werden, ob List eine Unterklasse von List ist oder nicht): Definitiv nützlich, ist der nutzerseitigen Varianz in Java (z.B. mit Wildcards) meist überlegen. Braucht trotzdem noch Feinschliff, weil es bei komplizierten Typhierarchien zu Problemen kommen kann.
Abstrakte Typmembers (ähnlich wie Generics, werden aber nicht teil der Signatur, sondern sind eher “innere Angelegenheit” der Klasse): Hin und wieder nützlich, aber schwer zu verstehen und anzuwenden. Keine klare Regel wann gegenüber Generice s zu bevorzugen. Würde ich eher drauf verzichten
Singleton-Klassen: Bis auf das bescheuerte Schlüsselwort “object” eine gute Idee. Die normalen Kritikpunkte an Singletons treffen hier nur bedingt zu, und wiegen nicht so schwer wie die Kritik am “static”-Konzept (was Scala über Singletons mit der Variante “Companion-Object” abgeschafft hat). Package-Objects können als weitere Variante davon gesehen werden
Implicits (und damit zusammenhängend View Bounds): Ermöglicht eine Art “Typklassen” (in gewisser Hinsicht flexibler als in Haskell), statisch getyptes “Ducktyping” und Dependency Injection. Definitiv eines der besten und mächtigsten Konzepte der Sprache, kann allerdings leicht missbraucht werden. Nach etwas Feinschliff bei den Scoping-Regeln definitiv nützlich.
Spezialisierungen: Möglichkeit, um Primitive effizient im generischen Umfeld zu verwenden, ist nur dem unzureichenden JVM-Typsystem geschuldet
Manifests: Reifizierbare Typen. Ist nur dem unzureichenden JVM-Typsystem geschuldet (Type-Erasure)
null: Eigentlich unnötig, nur der Java-Kompatibilität geschuldet
Traits: Sehr ähnlich zu Javas Interfaces mit Default-Methoden, beschränkte (statuslose) Mehrfachvererbung. Sehr nützlich, mittleres Missbrauchspotential. Können in Gegensatz zu Java auch direkt bei der Zuweisung “hineingemixt” werden: val x = new Foo with Bar with Baz
Value-Objekte Performante Wrapper, die vom Compiler wegoptimiert werden. Auch für Java vorgeschlagen (eventuell in Java 10)
Typen höherer Ordnung: Unverzichtbar, um höhere Abstraktionen (z.B. aus der Kategorientheorie: Funktoren, Monaden, Arrows) abbilden zu können. Sollten wie alle Generics nicht überstrapaziert werden (was zur Zeit bei den Scala-Collections der Fall ist). Bei sparsamer Verwendung nützlich, aber weniger in “normalem” Code, sonder eher in Bibliotheken. Grundprinzip ist leicht verständlich, die Details können aber haarig werden. Potentielle Konflikte mit Varianzen.
Ich finde die meisten Ideen gut, und denke, dass sie sich mit etwas Arbeit auch orthogonal und intuitiv verwendbar implementieren lassen. Teilweise werden schon die nützlicheren Sachen von anderen, konservativeren Sprachen übernommen (etwa definitionsseitige Varianzen in Kotlin).
In Java könnte ich mir Selbsttypen, definitionsseitige Varianzen, Manifests, Spezialisierungen, Value-Objekte und implizite Umwandlungen vorstellen, eventuell auch Typen höherer Ordnung und Typ-Aliases. Traits und Singletons (als einelementige Enums) hat Java schon, diese könnten entsprechend erweitert werden.
**Achtung: Kleiner OT **
(ich finde Scala übrigens ziemlich toll!)
[quote=Landei] Braucht trotzdem noch Feinschliff…kann allerdings leicht missbraucht werden… Nach etwas Feinschliff … um höhere Abstraktionen (z.B. aus der Kategorientheorie: Funktoren, Monaden, Arrows) abbilden zu können. …
nicht überstrapaziert werden…Bei sparsamer Verwendung nützlich, aber weniger in “normalem” Code…die Details können aber haarig werden.[/quote]
Manchmal sehne ich mich zurück zu QBASIC. Das wird alles so hyperkompliziert, kein Anfänger wird das alles jemals wirklich lernen, niemand wird ein paar Jahre später die Abstraktionen eines Super-Programmierers noch verstehen.
Unbedingt Kategorientheorie, ganz wichtig. Es wird nicht mehr lange dauern, und auch die Wörter Topos, Situs, Motiv und Grothendieck-Topologie werden im Grundstudium Informatik erläutert. Am Ende steht dann wahrscheinlich eine Kohomologietheorie für Software :ka:
Hoffentlich habe ich dann schon meinen Jazz-Club. Und mein Barmann mischt gute Drinks.
Naja, so abwegig ist das nicht. Im 1. Semester in Algebra muss man sowieso algebraische Strukturen lernen. Und von Körpern, Gruppen, etc. ist es ja dann nicht mehr weit zur Kategorientheorie. In der Lehrveranstaltung Typsysteme wird vor allem auf das typisierte Lambdakalkül und algebraische Strukturen als Grundlage für Typen eingegangen. Aber ein aufbauendes Fach dass da noch mal tiefer reingeht ist nicht so unwahrscheinlich.
Und offtopic ist das auch nicht. Funktionale Programmierung ist ein Randthema weil es komplexe Business Logik wunderschön abbildbar macht aber alles andere einfach nur ein Krampf ist. Das einzige große Projekt das ich kenne in dem funktionale Programmierung eine Rolle spielt war von der ÖBB. Dort wurde nur der Service der den richtige Tarif errechnet in Haskell geschrieben. Der Rest war Python für REST-Endpunkte und JS/HTML für das Frontend.
Mich würde es nicht wundern, wenn zukünftige Ausgaben von Clean Code & Co von der Verwendung der meisten “neuen Features” abraten. So toll das im Einzelfall auch alles sein kann, so schlimm finde ich die Auswüchse davon.
Dürfte ich mir eine Programmiersprache wünschen, wäre das schlicht Java 7 ohne Type Erasure und ohne new (konsequent DI).
Gruß
Fancy