Optional ifPresent() a "czystośc programowania" fukcyjnego

0

Optionale są terminem z FP.
Metoda

public void ifPresent(Consumer<? super T> consumer)

Wywołuje consumera jeśli jakas wartośc istnieje. Ale tak naprawde to czy nie jest troche sprzeczne z ideą FP? Jesli np. chcemy sprawdzic czy istnieje jakaś wartośc w tym Optionalu i np. zapisac ją do bazy danych?

employeeOptional.ifPresent(this::save);

Z tego co wiem raczej w strukturach monadycznych nie zmieniac stanu.
@jarekr000000 @Wibowit

0

Jak zapisujesz coś do DB, to to jest bardzo nie FP. Poza tym, zapisywanie może się nie powieść, więc powinno zwracać monadę, co oznacza, że nie używasz ifPresent tylko bind/andThen.

6

Optionale są terminem z FP.

Nie są terminem z FP, ale są z FP bardzo kojarzone. Przede wszystkim w FP mamy typy wyższych rzędów oraz metody na nich operujące, więc potrzebujemy typów które można zagnieżdżać. Dla przykładu możemy mieć metodę flatten która spłaszcza monady, z M<M<A>> robi M<A> czyli np z List<List<String>> robi List<String>, a z Optional<Optional<String>> robi Optional<String>. Nullable types się tutaj nie sprawdzą, bo nie ma wspólnego mianownika między nullable-types a kolekcjami czy innymi monadami. Nie ma String?? którego dałoby się spłaszczyć do String?.

Jak zapisujesz coś do DB, to to jest bardzo nie FP.

Jeżeli nie robisz żadnych efektów ubocznych to program efektywnie nic nie robi :] W FP efekty uboczne są, ale zawsze opakowane w coś.

Jeśli opierasz program o monady IO (tzn każdy efekt uboczny opakowujesz w monadę IO) to oczywiście musisz te wszystkie monady z sobą spiąć (flatMapem/ bindem zwykle) i zwrócić z metody, a potem pchać do góry aż do metody wejściowej.

Pytanie jak bardzo chcesz iść w "czystość" FP. Jeśli chcesz cały program oprzeć o monady IO to będziesz pisał Haskella w Javie. Bardziej opłaca się pisać Haskella w Haskellu. W językach które mieszają paradygmaty funkcyjne i obiektowe najlepiej jest rozdzielić kod imperatywny od kodu funkcyjnego, czyli mieć szeroki zbiór klas niemutowalnych (i bez efektów ubocznych) oraz część klas, które zarządzają wewnętrznym mutowalnym stanem i wywołują też inne efekty uboczne. W Scali bardzo często takim miejscem na efekty uboczne jest Akkowy aktor, który ma szereg fajnych właściwości - jednowątkowe przetwarzanie wiadomości w obrębie jednego aktora (a więc odpada sporo zabawy z synchronizacją), wiele aktorów działających naraz, hierarchiczna obsługa błędów, bardzo silna enkapsulacja (trzeba się sporo natrudzić i nahakować by z ActorRefa dostać się do lokalnej instancji aktora o ile takowa istnieje), itd

Klasy czysto funkcyjnie nie mogą korzystać z klas imperatywnych, ale klasy imperatywne już mogą i powinny jak najszerzej korzystać z klas czysto funkcyjnych. Czasami może się jednak zdarzyć iż np lokalna mutowalna mapa znacznie upraszcza kod, a efekty uboczne nie są obserwowalne z zewnątrz, więc taka lokalna optymalizacja jest akceptowalna - innymi słowy: nie zawsze warto pisać funkcyjnie tylko dlatego, że się da. Ważne jest jednak by unikać mutowalnego stanu nad którym ciężko zapanować, a więc przede wszystkim globalnego mutowalnego stanu. W Scali dla przykładu używanie niemutowalnych kolekcji jest zwykle przyjemniejsze niż używanie tych mutowalnych, więc to jest świetna zachęta do maksymalizowania funkcyjnej czystości w programie.

1

@scibi92 nie mieszajmy myślowo dwóch różnych systemów walutowych

  1. Są różne poziomy fp, Ty myślisz o pure fp, a to w javie wymaga dyscypliny (i nikt Ci nie pomaga).
  2. Problemem głównym jest save() bo to jest nieczyste. W pure fp save powinno Ci dać monadę IO, DBTransaction, czy nawet Future/Task.
  3. Samo ifPresent jest oczywiście też nieczyste, bo kończy się voidem.
  4. Gdybyś użył map i wylądował w czymś w stylu Option<IO<T>>, na którym byś zrobił getOrdefault to byłoby bardziej pure.

1 użytkowników online, w tym zalogowanych: 0, gości: 1