Seiteneffekt + Rückgabewert

aus anderem Thema abgespalten (Zitat führt dorthin):

wenn im Gegensatz zu remove-Methoden & Co. hier der Aufrufer den boolean für Rückgabe true/ false bereits vorgibt, dann ist da eigentlich gar keine eigene Responsibility mehr :wink:

nur noch eine technische Abkürz-Methode ähnlich ternären Operator a ? b : c


es geht schon noch um Methoden (nicht Funktionen) in Java? :wink: später gar Java-Collections genannt,
Seiteneffekte, Veränderung von mutable inneren Zustand oder von Parametern, ist das Wesen der Objektorientierung,
in der Mehrzahl aller Methoden vorhanden, nichts ‚zu vermeidendes‘

und Rückgabewert dabei auch noch geläufig, auch beides zusammen nichts ungewöhnliches,
wenn ich allein alle Fälle mit redirectToCategory() hier sehe… :

Dauerverletzung?

andere, funktioniale Denkweisen, haben für sich ja ihre Sonder-Daseinsberechtigung,
aber reicht als exotische Vorschläge, brauchst du nicht als vermeintlichen Standard/ Richtschnur zu verkaufen :wink:

[QUOTE=SlaterB]
andere, funktioniale Denkweisen, haben für sich ja ihre Sonder-Daseinsberechtigung,
aber reicht als exotische Vorschläge, brauchst du nicht als vermeintlichen Standard/ Richtschnur zu verkaufen ;)[/QUOTE]

Was soll das? Vermischung von Seiteneffekten und Berechnung von Rückgabewert ist problematisch, das hat nichts mit funktionaler Denkweise zu tun. Das SRP findest du auch in “Clean Code”.

Wie immer gibt es Ausnahmefälle (etwa wenn man ein Fluent Interface designed), aber normalerweise ist es einfach eine schlechte Idee.

Naja, so aus dem Kontext gerissen, sehe ich das wie @Landei . Es wirkt wie ein Design-Fehler.

Wenn ich mir dem Rückgabewert etwas anfangen möchte (und das nehme ich hier an) gehört das If-Statement vielleicht einfach in den Aufrufer, statt die Methode selbst.

Aber die Frage ist so abstrakt und ohne konkreteres Beispiel kann hier kaum geholfen werden.

[QUOTE=Landei]Vermischung von Seiteneffekten und Berechnung von Rückgabewert ist problematisch, das hat nichts mit funktionaler Denkweise zu tun. Das SRP findest du auch in „Clean Code“.

Wie immer gibt es Ausnahmefälle (etwa wenn man ein Fluent Interface designed), aber normalerweise ist es einfach eine schlechte Idee.[/QUOTE]
zum einen hast du Seiteneffekte an sich schon krititisiert, dabei Standard in Objekten mit Zustand, Bezug auf funktionale Denkweise

zum anderen ist auch pauschale Kritik an dieser Vermischung reichlich Unsinn,
wie sollte es jemals einen Zufallsgenerator geben wenn der nicht gleichzeitig einen neuen Wert berechnen und zurückgeben kann?
wie soll ein DB-Cache mit Laden, Cachen und Rückgabe funktionieren?
oder auch nur jede Lademethode für sich, falls DB-Zugriff schon als Seiteneffekt gilt?

zu trennen ist zwischen verschiedenen FACHLICHEN Aufgaben/ Responsibilities,
kein Verbot von sinnvollen Rückgabewert zur einen Aufgabe der Methode an sich

Rückgabe + Seiteneffekt in einzelnen Methoden findet sich in jedem Programm, wie immer nehme ich gerne fjorum für Beispiele, noch eins:

    public Category createNewCategory(String name, Category parent) {
        Category category = new Category(name, parent);
        return categoryRepository.save(category);
    }

ganz normal oder ist dein ganzer Code ‚problematisch‘? :wink:

Wie kommst du darauf? Natürlich kann man einen Zufallsgenerator ohne Seiteneffekte schreiben, auch in Java.

Naiv ginge das so:

RanGen rg = new RanGen(4711);
Pair<RanGen, Integer> pair = rg.next();
for(int i = 0; i < 100; i++) {
   System.out.println(pair.second());
   Pair<RanGen, Integer> pair = pair.first().next(); 
} 

RanGen wäre hier immutable, und next liefert immer das gleiche Ergebnis. Natürlich liefert der im Ergebnis mitgelieferte **neue **Generator auch wieder neue Werte.

Es gibt auch deutlich bequemere Lösungen, aber da die das böse Wort „Monade“ enthalten, kann ich mir gleich die Mühe sparen, das zu erklären.

Ich habe jedenfalls das Gefühl, dass du in dieser Richtung noch nicht einmal versuchst, ein wenig deine Vorstellungskraft zu bemühen. „Immutable Zufallsgeneratoren, so ein Schmarrn! Und wo kämen wir denn da hin? Schon unsere Großväter haben mutable Zufallsgeneratoren…“ :grampa: Du beschränkst dich nur selbst mit so einer Denkweise.

wozu Pair, wieso nicht einfach

    for(int i = 0; i < 100; i++) {
       rg  = rg.nextWithInt(); // neuer RanGen..
       System.out.println(rg.getInt()); // liefert den intern abgelegten aktuellen Zufallswert
    }

?

theoretisch aufschreiben kann man solche Auswüchse natürlich, immerhin nahe dran an sonstiger Funktionalität,
aber wozu?

wenn ich es richtig sehe, dann wird selbst in Scala

Random mutable gebaut? :wink:
bzw. schlicht java.util.Random genutzt…
Scala - Random.scala - cc, cc, int, int, random, random

ich schiebe lächerlichen Unsinn in meiner Denkweise an den Rand…

Aha, erst ist es “undenkbar”, jetzt nur noch “theoretisch”, ein “Auswuchs” und “Unsinn”.

Das Pair stört dich so sehr? Bitteschön:

public class RanGen {

    public final int value;
    private final int nextSeed;

    public RanGen(int seed) {
        value = seed % 257 +  (seed ^ 123456789) + 987654321;
        nextSeed = (seed ^ value) * (143958743 + seed % 13) + value * 37;
    }

    public RanGen getRanGen() {
        return new RanGen(nextSeed);
    }
}

Verwendung ist jetzt einfach wie Kuchenessen:

RanGen ranGen = new RanGen(500);
for(int i = 0; i < 100; i++) {
    System.out.println(ranGen.value);
    ranGen = ranGen.getRanGen();
}

Noch was zu meckern (außer über die Qualität der Zufallszahlen, das ist natürlich nur ein zusammengehacktes Beispiel)?

Wirklich, deine Beiträge wirken, als ob du dir die Finger in die Ohren steckst und “Lalalala, ich kann dich hören” rufst.

Was die fjorum-Beispiele angeht: Mit Hibernate oder gängigen Web-Frameworks lässt sich momentan nur so arbeiten. Es gibt Alternativen (z.B. FRP-Frameworks zur Web-Programmierung), aber die sind noch nicht so richtig in Java angekommen.

aktueller Stand:
Ursprungsbehauptung 1 ‚Seiteneffekt zu vermeiden‘ - Unsinn
Ursprungsbehauptung 2 ‚Seiteneffekt + Rückgabewert problematisch‘ - Unsinn

Aufhängen an einem Random-Beispiel welches nirgendwo auf der Welt real eingesetzt wird, nicht mal in Scala (!)
(edit: „Das Pair stört dich so sehr? Bitteschön:“ ist das nicht dasselbe, was ich schon als Alternative gepostet habe? wieso nochmal? :wink: )
sondern selbstverständlich überall Randoms mit dem bösen bösen Seiteneffekt + Rückgabewert

dazu diverse persönliche Beleidigungen

starkes Zeugnis…


ah klar, mit allem gängigen läßt sich nur so arbeiten, in allen Java-Programmen der Welt,
aber man kann das Normale hier einfach so als problematischen Stand darstellen…


soviel zur Behauptung, es ginge unnötig um Funktionalität…

Es geht noch ein bisschen weiter, aber ich will das Buch nicht abtippen. Ich stimme auch nicht allem in „Clean Code“ zu, aber das ist einer der vernünftigsten Ratschläge im ganzen Buch. Nebenbei wird hier mit keinem Wort „funktionale Programmierung“ erwähnt (höchsten von „Funktion“ gesprochen, wo genaugenommen „Methode“ gemeint ist).

das ist ein vernünftiger Ratschlag weil unvernünftig aussehender Code krititisiert wird,

aber wenn eine solche ähnliche Sache dauerhaft nötig ist wie Set nicht nur remove sondern auch add oder noch anschaulicher Stack.pop(),
dann wird jeder nach der dritten Codestelle mit if (x schon vorhanden) .. else add(x) eine derartige abkürzende Methode schreiben,

genau wie Random, DB-Cache und 1000 andere Dinge,
eine sinnvolle Rückgabe passend zur Aufgabe (inklusive Änderung) einer sinnvoll benannten Methode ist normaler Standard,

aber natürlich ja: so wie jede zwei Code-Befehle oder sonstige zwei Dinge auf der Welt, die unvernünftig kombiniert werden,
so kann auch eine Aktion X = Objekt ändern und Y = Rückgabewert zusammen unnötig sein,

genauso auch wie zwei Dinge die nicht zusammenpassen in einer Rückgabe, einem Pair zurückzugeben :wink: ,
auch wenn das nicht in einem Buch steht, aber das nur als allgemeiner Scherz, hier nicht vorkommend


Offtopic:

bei

Was bedeutet dies? Fragt die Anweisung, ob das „username“-Attribut vorher auf „unclebob“ gesetzt war? Oder fragt sie, ob das „username“-Attribut erfolgreich auf „unclebob“ gesetzt worden ist? Est schwer, die Bedeutung aus dem Aufruf abzuleiten, weil nicht klar ist, ob das Wort „set“ ein Verb oder ein Adjektiv ist."

fällt mir Code wie

    .orElse(half(y)).map(Optional::of)
    .orElse(half(z))
    .map(n -> "the result is " + n)
    .orElse("all numbers were odd");

ein…

auch das ist jede Menge zusammengedrängter Code bei dem man sich ständig fragen kann, was jeweils die wenigen immer gleichen Verben gerade für eine Aufgabe haben, ob in Zeile 3 zwischenzeitlich eine große Liste entstanden und wieder zusammengedampft wird oder doch nur die ganze Zeit ein String bearbeitet wird

vielleicht dazu auch ein Beispiel nehmen, mehr einzelne ifs und for-Schleifen mit klarer Bedeutung/ Code-Struktur haben auch ihren Reiz

[QUOTE=SlaterB]
Offtopic:

bei

Was bedeutet dies? Fragt die Anweisung, ob das „username“-Attribut vorher auf „unclebob“ gesetzt war? Oder fragt sie, ob das „username“-Attribut erfolgreich auf „unclebob“ gesetzt worden ist? Est schwer, die Bedeutung aus dem Aufruf abzuleiten, weil nicht klar ist, ob das Wort „set“ ein Verb oder ein Adjektiv ist."

fällt mir Code wie

    .orElse(half(y)).map(Optional::of)
    .orElse(half(z))
    .map(n -> "the result is " + n)
    .orElse("all numbers were odd");

ein…

auch das ist jede Menge zusammengedrängter Code bei dem man sich ständig fragen kann, was jeweils die wenigen immer gleichen Verben gerade für eine Aufgabe haben, ob in Zeile 3 zwischenzeitlich eine große Liste entstanden und wieder zusammengedampft wird oder doch nur die ganze Zeit ein String bearbeitet wird

vielleicht dazu auch ein Beispiel nehmen, mehr einzelne ifs und for-Schleifen mit klarer Bedeutung/ Code-Struktur haben auch ihren Reiz[/QUOTE]

Das sind aber zwei vollkommen verschiedene Dinge. Das Beispiel in Clean Code bezieht sich darauf, dass es nicht klar ist, was der Rückgabewert bedeutet, weil dies nicht aus dem Methodennamen hervorgeht.
In deinem Codebeispiel ist das Problem, dass der funktionale Stil für den gemeinen Java-Programmierer ungewohnt und daher erst einmal schwerer zu verstehen ist. Die Bedeutung der einzelnen Rückgabewerte ist jedoch absolut eindeutig (ok, die Definition von half fehlt natürlich, aus dem Kontext ist aber ersichtlich, dass ein Optional<Integer> zurückgegeben wird, der empty ist, wenn die eingegebene Zahl ungerade ist und die Hälfte des eingegebenen Wertes, wenn er gerade ist).

deswegen stand ja Offtopic dran, es ist was anderes :wink:
die Unklarheit wird aber nie verschwinden, Codewüsten bleiben Codewüsten, vor 50 Jahren, heute, in 50 Jahren


was mit nebenbei noch einfiel:
eine Umwandlung des Buchbeispiels
if(set("username","unclebob"))...
auf


x.set("username","unclebob"); // setzt intern boolean, auch immutable mit x = x.set(..) möglich
if(x.wasSet())...

würde quasi die gleichen Fragen stellen,
was liefert wasSet(), ob schon vorher etwas gesetzt war, oder ob neu etwas gesetzt wurde?
hatte das set() nun eine Änderung oder nicht?

obwohl der Regel komform, die set-Methode ohne Rückgabe, nach dem Buch lebend keine Probleme vorhanden,
ist fachlich kaum ein Unterschied, so kompliziert wie vorher,

ob man eine Rückmeldung möchte oder einen Wert zur Änderung braucht ist eine fachliche Frage,
sowas muss eben gelöst werden, etwa durch besser benannte Methoden und deren Doku

Rückgabewert oder Verzicht darauf spielt keine große Rolle, die aufgetrennte Variante kann genauso gut noch komplizierter sein,
deswegen baut man solche Methoden mit nötiger Rückmeldung eben doch so wie sie überall vorhanden sind:
Seiteneffekt + Rückgabe zusammen

beides zusammen kann Probleme machen, nicht beides zusammen genauso,
alles kann letztlich irgendwann (vor allem falsch eingesetzt) Probleme machen, eine pauschale Aussage ohne Wert

edit:
für immutable natürlich Seiteneffekt + Rückgabe unmöglich,
deswegen Random nicht immutable in Scala,
eine DB-Session usw., das wäre immutable auch ein schöner Spaß, gibt es wohl nicht?

immutable ist im Kleinen gut, aber eine bedenkliche Selbstbeschränkung wenn zu stark eingesetzt,