Reasoning about code

[QUOTE=Marco13]Der Vergleich bzw. die Nachfrage nach “Swing mit Scala” hinkt auf mehreren Ebenen - ganz vordergründig schon auf der, dass Swing eben Objektorientiert ist, und einige (selbst in dieser Hinsicht fragwürdige) Konzepte aus den 90ern mitschleift.

[…]

Das Argument der Parallelisierung einfach so wegzuwischen greift auch etwas zu kurz. Gerade weil man Funktionale Elemente (oder sogar direkt Scala) weniger im GUI unterbringen würde, sondern eher im “backend”, wo irgendwelche Datentransformationen gemacht werden. [/QUOTE]
muss ja nicht Swing sein sondern eben die Scala-GUI-Variante,

Programmiersprachen sind doch immer noch dafür da normale Programme zu schreiben, oder?
es werden ja wohl in Scala exakt dieselben normalen Programme wie in Java geschrieben,
eben mit GUI, mit Datei einlesen, Person-Objekte aus DB laden usw., der ganz normale Allerweltscode,
oder sollte Scala keine Allgemeinsprache sein?

‘funktionale Elemente weniger in GUI’ verstehe ich nicht recht,
das Ziel ist ja anscheinend, auch für Stream in Java, die Schleifen und das if komplett zu entfernen, tritt überall auf

Nun, eine technisch-fundierte Bewertung von Scala der Eignung von Scala für GUIs will ich mir mal nicht anmaßen (oder überhaupt eine Aussage über Scala :D). Es gibt (schnell gewebsucht) wohl ein Swing-Package, das die Swing-Verwendung konziser macht. Ich könnte mir vorstellen, dass Dinge wie JavaFX da sogar noch besser ins Konzept passen. Aber (auch in bezug auf den zweiten Teil) ich sehe funktionale Programmierung eher in anderen Bereichen als hilfreich an. (Ich meine, zustandsfrei … ein GUI?), und sie soll sicher nicht alle imperativen Konzepte ersetzen.

Ich stimme dir in fast in allen Punkten zu. Aber da muss dann doch sagen, wenn man das ganze „Reactive“ macht, funktioniert das überraschend gut. Aber dazu muss auch das dahinterliegende Programmkonstrukt passen.

Z.B. sieht der Code von Elm-Projekten gar nicht so schlecht aus wenn man sich erst mal eingelesen hat: elm-lang.org

die Richtung habe ich schon lange nicht mehr gehört, denkt @Landei ähnlich?

der Link am Anfang spricht doch davon die normalen Probleme/ alles mit Islation & Co. sauberer zu behandeln,
die einfachen Scala-/ Java8-Beispiele behandeln auch Konsolenausgabe
oder wie getEvenNumbers() bzw. dein Beispiel List<Result> results = largeList.stream .. ganz normale Aufgaben,

im Prozess vielleicht zustandsfrei/-sparsam, aber durchaus mit dem Ziel, einen Zustand in den nächsten zu überführen, in objektorientierter Welt,
ist nun Scala/ Java8 turingvollständig für alles die (je nach Meinung) bessere Lösung oder nicht, bin verwirrt :wink:

Bei der Web-GUI-Programierung ist doch z.B. gerade React “der Shit”. FRP ist nicht einfach, und man ist da wohl auch noch in einem Lernprozess, aber ich denke, es wird sich langfristig durchsetzen.

Um noch einmal auf den Ausgangsartikel zurückzukommen: Einen wichtiger Aspekt wurde da gar nicht erwähnt, nämlich die erweiterten Abstraktionsmöglichkeiten. Angenommen, man hat eine ganz gewöhnliche Schleife:

List<Foo> foos = ...
List<Bar> bars = new ArrayList<>();
for(Foo foo : foos) {
    bars.add(foo.getBar());
}

Die Listen-Implementierung hat hier überhaupt keine Wahl, wie sie diesen Transformationsprozess umsetzt. Die Iteration ist explizit, sie kann z.B. nicht lazy erfolgen. Stattdessen könnte eine map-Methode auf List (wenn es das im Collection-Framework gäbe) eine immutable Liste liefern, die vollständig lazy ist und so gut wie keinen zusätzlichen Speicher benötigt:

public class MyList<T> implements List<T> {
   ...
   public <U> List<U> map(Function<T,U> function) {
       return new AbstractList<U>() {
            ...
            public U get(int index) {
                return function.apply(MyList.this.get(index));
            }
            ...
       };
   }
} 

Diese Flexibilität, die dem Nutzer durch einfaches Austauschen der Listen-Implementierungen zur Verfügung steht, lässt sich mit dem imperativen Code einfach nicht erreichen. Der Haupt-Unterschied zwischen einer for-Schleife und myFooList.map(foo -> foo.getBar()) ist nicht, dass letzteres kürzer ist, sondern dass es ausdrückt, **was **man will, und nicht wie. Es ist der Unterschied zwischen “ich will nach München fahren” und “ich öffne die linke vordere Autotür, ich nehme auf dem linken vorderen Sitz platz, ich stecke den Schlüssel ins Schloss…”. Und das ändert letztendlich auch die Denkweise, weil es den Fokus weg von der Durchführung hin auf das Ziel lenkt (“vielleicht komme ich besser mit der Bahn nach München?”).

auch nicht mit

    bars.add(bar);
}

oder

for(Bar bar : function.map(foos)) {
    bars.add(bar);
}

edit: oder auch genauso mit myList:

for(Bar bar : foos.map(function)) {
    bars.add(bar);
}


oder

for(Foo foo : foos) {
    Bar bar = function.getBar(foo);
    bars.add(bar);
}

oder was immer man möchte?
wo ist die Einschränkung, was erfordert hier so dringend den dramatischen Wechsel auf neue Syntax?
was ist daran nicht imperativ?
Iteratoren sind ja schon bekannt mächtig, lassen mit einem Wrapper ein Array durchlaufen oder dynamisch neue Werte erzeugen, alles nix neues

vieles davon baut manch einer schon vor Java8 in Helper-Methoden oder Funktionen/ Iteratoren nach, wenn in seltenen Fällen wirklich nützlich,
fertige APIs und einheitliche Klassen/ Interface wie Function können dabei nicht schaden, wenn genauso selten eingesetzt,
aber deswegen muss ja nicht die Programmiersprache geändert werden


für einfache Beispiele wie myFooList.map(foo -> foo.getBar()) ist das Bauen eines Funktionsobjektes, zumal in der alten Syntax, eher lästig,
aber in diesem Fall ja auch ganz verzichtbar:

    Bar bar = foo.getBar();
    bars.add(bar);
}

bzw. was du selber anfangs schriebst:

for(Foo foo : foos) {
    bars.add(foo.getBar());
}

das ist ja wohl noch kürzer und dazu lesbar ohne exotisches map() und Pfeile im Code


damit hat man in der Programmierung ganz schlechte Karten,
für Methoden anderer Klassen, Polymorphie usw. mag man ja das Blackbox-Prinzip hochhalten,

aber innerhalb einer Methode, in echten Code, in einer Schleifenverarbeitung, die der Programmierer lesen, verändern, erst selber bauen muss,
ist es ungemein wichtig zu verstehen WIE etwas passiert, die Kontrolle über den Code haben, die Ausführung nachvollziehen, bei Bugs in die kleinsten Einzelschritte hineinzuschauen,
Performance zu beurteilen und deswegen zwischen ArrayList und LinkedList zu wählen usw.

Assembler kann man nicht lesen, Klartext ist kein Programm,
die magische Mitte ist eine Programmiersprache, die mit überschaubar vielen bzw. wenigen und dabei lesbaren, ausführungsnachvollziehbaren Schritten komplexe Arbeit erledigt,
diese Magie hat die Welt imperativ in ein neues Zeitalter geführt, geht zum Glück nicht verloren

Dem stimm ich uneingeschraenkt zu.

Nur der Vollstaendigkeit halber: Es gibt zwei FRP’s. Das eine (das urspruengliche) ist von 1994 von Conal Elliott, das andere erlebt seit ein paar Jahren einen gewissen Hype, vor allem durch Evan Czaplicki mit seinem Elm.
Beide haben nur ziemlich wenig miteinander zu tun und Elliott ist nicht besonders gluecklich ueber die neuerliche Entwicklung.

Elliots Idee ist, ein nicht-diskretes funktionales System zu bauen, also seine Software so zu gestalten, dass die Zeit nicht in irgendwelchen kleinsten Zeiteinheiten berechnet wird (z.B. bei einer Simulation), sondern dass die Zeit quasi beliebig genau sein kann. Gibt auch ein paar youtube Videos dazu - allerdings sind die ziemlich einschlaefernd :wink:

Elm dagegen ist eine FRP (functional reactive programming) Umgebung, bei der die meisten Konzepte von FRP umgesetzt werden koennen. Im Kern laeuft das darauf hinaus, dass der Code keine Liste von Statements ist. Sondern ein Graph, durch den die Daten fließen (wobei jeder Knoten im Graph eine pure function ist).

Natuerlich kann man auch in Java FRP programmieren. Z.B. ist ReactiveX oder ReactFX eine Moeglichkeit dazu. Genauso wie die Java8 Streams (wobei diese die wohl allerschlechtest moegliche Implementierung ist). Allerdings ist eben nicht sichergestellt, dass der Entwickler immer seiteneffektfreie Funktionen benutzt (siehe Mutables).

@SlaterB : Das Problem mit den for Schleifen ist, dass man auf die Idee kommen koennte, die Liste ueber die iteriert wird, zu veraendern. Z.B. weil die Liste asynchron uebers Netzwerk gelesen wird. Natuerlich kann man das anders machen - nur ist das eben deutlich aufwendiger (brauch zwei Listen, die ich irgendwann synchronisere, etc). Dieses Problem existiert bei FRP nicht.

Anderes Beispiel ist noch REST. Im Endeffekt ist das nichts anderes, als funktional programmieren - nur eben bezueglich verteilter Systeme (z.B WebServices, Buzzword: Microservices). Und hier liegt der Vorteil auf der Hand: richtig programmierte REST Services skalieren einfach extrem gut.

PS: ReactJS von Facebook ist ein FRP System in JavaScript fuer HTML. Ziemlich cooles sogar :wink:

nun, man kann vieles,
auch im Code

public class MyList<T> implements List<T> {
   ...
   public <U> List<U> map(Function<T,U> function) {
       return new AbstractList<U>() {
            ...
            public U get(int index) {
                return function.apply(MyList.this.get(index));
            }
            ...
       };
   }
} 

in get() bei Index 50 der function-Variablen eine andere Funktion zuweisen,
aber man macht es doch in der Regel nicht…

ConcurrentModificationException ist da, Immutable-Liste zur Not,
alles kein rechter Grund für neues Programmiermodell,

ist natürlich gewiss auch nicht der einzige Grund, klar


erinnert mich gerade an Optional und die struktuelle Vermeidung vor NullPointerExceptions,

man kann Programme durchaus wie mathematische Beweise aufbauen, mit Invarianten vor Standardproblemchen geschützt,
nur hilft dieser Ansatz nicht wenn jede Kleinmethode zu einem Kunstwerk zum Bauen und Schatzkarte zum Lesen wird,

das macht sich gut in schicken Beispielen und vielleicht in Code mit 10fach-Sicherheitsanforderung wie Kernkraftwerk, Kosten für Erstellung und Unterhalt egal,
aber ist kein realer Ansatz für normale Probleme in der Welt

Klar, aber es gibt auch keinen Grund, das nicht zumindest mal auszuprobieren :wink:

Grad fuer GUI Code, der mit Java irgendwie immer dazu tendiert, schrecklich zu werden.

Bei Elm (ReactJS fuehlt sich aehnlich an) konkret laeuft das so, es gibt quasi eine Funktion render(state):vdom, die bekommt den Zustand der Anwendung und wandelt diesen in HTML um. Die Elm-Runtime berechnet dann den Unterschied zwischen dem letzten HTML und dem neuen und schickt die Aenderungen zum DOM im Browser.

Das coole ist, in der render Funktion muss man nur codieren, wie die GUI fuer den gegebenen State aussieht - keine nervigen onIrgendwas(Event)-Hoellen mehr.

wie auch immer es gerade zu Elm kommt, Spezialanwendungen mit fertigen Grundfunktionen und neuen Schlüsselwörtern haben es immer leichter,
kein imperatives (oder funktionales) Programm könnte mal eben SQL-Mächtigkeit (und Übersichtlichkeit) erreichen

interessanter ist dagegen, wie die SQL oder Elm-Runtime programmiert ist :wink:


bei dieser Gelegenheit zu Elm reingeschaut:
ist example/adventure ein gutes Beispiel, kann man daran irgendetwas interessantes erkennen?

scheint mir nicht groß abweichend zu Java-Programmen wie aus Quaxli-Tutorial
(https://forum.byte-welt.net/java-forum/spiele-und-multimedia-programmierung/5049-quaxlis-spiele-tutorial.html),
es gibt ein Model mit veränderbaren Inhalt, Tasten setzen Status-Variablen, ein konstanter Timer/ Thread sorgt für wiederholte Positionsberechnung + generelles Repaint

Syntax in Java etwas rustikaler, dafür die gleiche wie zur Webserver-Programmierung, in Elm sicher nicht gewagt,
Swing mit Unterstützung für Tastatur-Events usw. kann man natürlich immer verbessern, ein Framework unter vielen


erfreulich nebenbei, in Elm auch menschenlesbaren Code wie

newVel n =
      if x == 0 || y == 0 then
        scale * toFloat n
      else
        scale * toFloat n / sqrt 2

statt

newVel n = (x,y).stream(filter(both zero -> 1/ sqrt), blah blah)

zu lesen, imperativer Code bewährt sich eben

Mal was um den Blutdruck wieder in Wallung zu bringen

Code Examples | Wrap Your Database in Java 8

Damit kann man dann, genauso unlesbaren, exotischen Code schreiben um seine Datenbanken zu verwalten.

Geb ich dir erstmal Recht. Aber du musst zumindest auch den Vorteil sehen: Der Code ist nun - im Gegensatz zu SQL - getypt. Du kannst keine Zahl mit einem String vergleichen, was bei SQL zu einer Exception fuehrt, ist im Fall von Speedment nicht compile-faehig. Obendrauf kommt noch, das ueberlebt Refactorings - im Gegensatz zu SQL.

Wie wichtig dir das ist, musst du selbst entscheiden :wink:

Fuer solche Dinge ist glaub ich wirklich eine alternative Sprache (neben Java) deutlich sinnvoller, als solche Sachen auf Krampf in Java reinzubauen. Aber seit Oracle da den Hut aufhat, wird irgendwie alles nur noch schlimmer :frowning:

[quote=schalentier]Du kannst keine Zahl mit einem String vergleichen, was bei SQL zu einer Exception fuehrt[/quote]Das hängt wohl von der DB ab. Oracle beispielsweise macht das klaglos, was eigentlich schlimmer als eine Exception ist…

bye
TT

der Satz war doch sicher ironisch zitierend, der Link auf Speedment als Positivbeispiel gedacht :wink:
bietet ja auch viel fürs Geld

aber ganz schön gefährlich teilweise, werden da Listen durchlaufen und für jeden Wert einzelne Subqueries gestartet?
kein Wunder dass dann parallel() ins Spiel kommt…, anders ja nicht zu schaffen

vieles wäre a la Hibernate-Criteria auch schon vor Java8 gegangen

Der Verweis auf speedment sollte eigentlich in Bezug auf dieses Statement von SlaterB gesehen werden

kein imperatives (oder funktionales) Programm könnte mal eben SQL-Mächtigkeit (und Übersichtlichkeit) erreichen

Dort wird, so wie ich das sehe, die Syntax von der Java Stream Api genommen und daraus eine DSL gemacht um damit SQL zu ersetzen/vermeiden.

Sollte das ganze funktionieren (Produktionsreife erreichen) dann sind die Vorteile auf der Hand.
Typisierung an stelle von Strings
Keine weitere Sprache (SQL) nötig

Und, wenn man sich auf die Stream Api einlässt und damit zurecht kommt auch kein neues Gedankenmodel bei der Verarbeitung von Datenbankabfragen. *

Hatte auch schon längere Diskussionen ob JDBC/SQL vs. JPA/Hibernate verwendet werden soll, die dann zugunsten ersterem entschieden wurden was jedoch nicht an mir lag.

[*] Microsoft geht hier den umgekehrten Weg. Mit Linq kann man SQL ähnliche Anfragen auf diverseste Datenstrukturen machen und eben auch auf SQL.