functional programming

Gdzie na pewno ‘null’ to za mało

Posted on Updated on

Nie lubię nulli. Uważam że są nadużywane. A dodatkowo powinno się korzystać z rozszerzeń typu Option<T>, zeby explicite zaznaczyć brak wartości. Dzisiaj trafiłem na przykład który jest dosyć bliski każdemu i może produkować niejednoznaczne wyniki.

When null is not enough: an option type for C#

Na przykład metoda FirstOrDefault. Mając pustą listę stringów, FirstOrDefault wskazuje brak pierwszej wartości poprzez zwrócenie nulla. Ale mając listę rozpoczynająca się nullowym stringiem także zwróci null. Rozróżnienie tych dwóch przypadków jest często istotne, ale FirstOrDefault nie zrobi tego za ciebie (pomimo posiadania koniecznej logiki). Może zrefaktorować FirstOrDefault, aby rozróżniała między tymi dwoma przypadkami…, ale co powinna zwrócić? Odpowiedzią jest: typ opcji.

Option zamiast wzorca TryGetValue(…, out value)

Posted on

Przedstawię dziś klasę całkiem naturalną z punktu widzenia programisty funkcyjnego. Gdyby to przełożyć na język bliski naturalnemu to jest to konstrukcja, która “albo posiada wartość zadeklarowanego typu, albo tej wartości nie ma”. Posłużę się od razu przykładami.

Są przypadki, gdzie nie wiemy czy dostaniemy wartość czy nie. Klasyczny przypadek to parsowanie. Gdy korzystamy z wzorca TryGetX kod wygląda:

int value;
if(int.TryParse(currentLine, out value))
{
    // happy path
}
else
{
    // else path
}

Typ ten można przekazywać dalej do innych funkcji lub zwracać z aktualnej funkcji. Dzięki temu dalej w flow działania aplikacji nie potrzebujemy 2 różnych funkcji przyjmujących raz happy path a raz failure path. Ostatecznie na końcu i tak trzeba “rozpakować” tą wartość, ale po drodze mogą zdarzyć się na przykład funkcje logujące, albo obsługujące wspólnie “brak danych” jak np HTTP 404. W przykładzie z TryGetX() wiadomość o sukcesie mamy tylko

var maybeResult = GetResults(data);
if(maybeResult.HasValue == false)
{
    return HttpStatusCode.NotFound; // 404
}

Jak na przykład może wyglądać taka klasa (inne nazwy to Maybe):

Kiedy niestety trzeba użyć metody zwracającej ‘void’

Posted on Updated on

Poczatkowo mialem metode która udawała metode “pure” (nie modyfikującą danych wejściowych).

        customerAccounts = UpdateCustomerAccountsWithIssues(customerAccounts);


        private IEnumerable<CustomerAccount> UpdateCustomerAccountsWithIssues(IEnumerable<CustomerAccount> customerAccounts)
        {
            foreach (var customerAccount in customerAccounts)
            {
                customerAccount.IssuesCount = _notificationsService.CountByCustomerAccountId(customerAccount.Id);
            }

            return customerAccounts;
        }

ale jest to gorsze bo tylko zaciemnia to, że w rzeczywistości modyfikujemy dane wejściowe. Tworzenie w tym momencie kopii wszystkich customerAccounts jest zbyt kosztowne i nie jest aż tak niezbędne.

Lepiej więc gdy metoda explicite mówi co robi:

        UpdateCustomerAccountsWithIssues(customerAccounts);


        private void UpdateCustomerAccountsWithIssues(IEnumerable<CustomerAccount> customerAccounts)
        {
            foreach (var customerAccount in customerAccounts)
            {
                customerAccount.IssuesCount = _notificationsService.CountByCustomerAccountId(customerAccount.Id);
            }
        }