Używacie monady Option/Maybe w swoich projektach?

0
obscurity napisał(a):

Do Optionala też możesz wstawić null i wszystko się sypie.

czemu niby? Normalna rzecz. Skoro typ który akceptuje null to jest first-class citizen (a w c# wygląda że jest), to powinno się go dać móc wsadzić do Optionala, tak samo jak do listy.

obscurity napisał(a):

W C# jest nullable, masz ??, możesz pisać extensiony do nullable jeśli chcesz podobny experience do Optionali i kod jest dużo bardziej czytelny.

Dla moich oczu to wygląda tak, że Microsoft daje 20 różnych tooli do handlowania "nullable", ale totalnie 0 do usuwania nulli z kodu, czyli to co powinni zrobić.

PS: no dobra, jest ten WarningToErrors o który mówili wcześniej no to jest 1.

1
Saalin napisał(a):

Pisząc w C# trzeba się przyzwyczaić do tego, że si-szaropowcy w kontekście monady Maybe są na poziomie Optional.isPresent z Javy i żadnymi mapami/flatmapami nie są zainteresowani.

Faktycznie

foo.map(p => p.getSomething())

jest dużo lepsze niż

foo?.something

Pokaż mi jeden przykład w którym kod z Optionalami jest ładniejszy. W javie te monady są potrzebne żeby łatać ułomności tego języka. Można je sobie zakodzić w C# jako extensiony jeśli ktoś preferuje taki styl

3

Z faktycznie skopanych rzeczy w C# jeżeli chodzi o ?, to:

public static void Test<T>(T? a)
{
    Console.WriteLine(a is null);
}

public static void Test2<T>(T? a) where T : struct
{
    Console.WriteLine(a is null);
}	

public static void Test3<T>(T? a) where T : class
{
    Console.WriteLine(a is null);
}

public static void Main()
{
    Test<int>(default); // False
    Test2<int>(default); // True
    Test3<Program>(default); // True
}
5
obscurity napisał(a):

Pokaż mi jeden przykład w którym kod z Optionalami jest ładniejszy. W javie te monady są potrzebne żeby łatać ułomności tego języka. Można je sobie zakodzić w C# jako extensiony jeśli ktoś preferuje taki styl

Pomijając, że java jest skopana, to jest akurat odwrotnie. Monady to normalka (jest ich troszkę więcej niż Optional). A wynalazki typu nullable, ? to łatanie ułomności języka, któremu ktoś na początku przypadkiem wsadził null i trzeba teraz coś z tym fantem robić. (Kotlin, którego czasem używam ma tu tak samo jak C#).

A przykład, gdzie widać przewagę monad to np. Scala:

for {
 u <- findUser(id)
 g <- findUserGroup(u)
 adm <- findAdmin(g)
} yield  adm.email

Przewaga tego polega na tym, że niezależnie czy findUser() i kolejne zwraca Optional, Try, czy Either (zwane inaczej Result) a nawet Task/Future to kod pozostaje taki sam. I to jest akurat rzecz, którą się robi (zmienia monady zwracane przez metody). (* oczywiście jest też wada, polegająca na tym, że jeśli metody będą zwracać różne monady np. findUser zwraca Optional, findUserGroup -> Try, a findAdmin -> Either to ten kod trzeba już będzie dopasować i przestanie być ładny).

2
AdamWox napisał(a):

W C# przecież jest nullable 🤔 po co komplikować projekt jakimiś bibliotekami?

nullable jest przecież całkowitą odwrotnością optionala, pozwala na używanie null tam, gdzie go miało nie być, zamiast zwracania pustej wartości.

AdamWox napisał(a):

Co to znaczy "nie działa"? Oczywiście, że może i widać to przecież na moim screenie, że VS informuje o tym. Jeśli chcesz poinformować siebie, że ta lista może przyjąć null to robisz List? list, wtedy VS ci "podkreśli" jak będziesz chciał zrobić list.Where() albo inne linq. To nie ma zablokować kompilacji, bo kod jest poprawny przecież. To problem programisty, czy to obsłuży, czy nie.

Tyle, że języki powinny zmniejszać liczbę problemów programisty, a nie ją zwiększać.

AdamWox napisał(a):

Zaznaczam, że wątek jest o przypisaniu śmiesznego Option z zewnętrzenej biblioteki, aby nulla nie było, a to się kompletnie niczym nie różni od przypisania temu obiektowi domyślnej wartości bez biblioteki 🤔 już pomijając, czy nullable w C# ma sens, czy nie

Ale jaką domyślna wartością? null to nie jest żadna wartość, to jest brak referencji.
Różnica taka jak między trzymaniem w ręce pustego portfela, a brakiem ręki.

Z bardziej pragmatycznego punktu widzenia - nie pozwala na modelowanie silnie typowanego i spójnego przepływu danych, trzeba ifować kod jak zwierzęta programiści C.

some_ONE napisał(a):

To pokaż mi jak przypisujesz null do takiego typu mając <Nullable>enable</Nullable> i <WarningsAsErrors>Nullable</WarningsAsErrors>.

Pomijając jakieś cuda z refleksją żeby celowo popsuć kod.

Proszę bardzo:

string s = null!;

Fajne te wszystkie nullowe errory, szkoda, że wystarczy jeden wykrzyknik, aby je wyłączyć. Zwłaszcza w takim kontekście to wygląda absurdalnie. 🙂

Do tego włączenie tych opcji broni nas jedynie w ramach własnego kodu. W przypadku jakichkolwiek interakcji z zewnętrznymi bibliotekami, są duże szanse, żenull i tak przyjdzie, więc trzeba się przed nim zabezpieczyć, więc zysk taki, że mamy może 20% nullowej ifologi mniej.

Odpowiadając na pytanie - nie, nie używam tych monad, bo nie widzę ich sensu, stosuję Result<T> i Null Object Pattern.

1
somekind napisał(a):
AdamWox napisał(a):

W C# przecież jest nullable 🤔 po co komplikować projekt jakimiś bibliotekami?

nullable jest przecież całkowitą odwrotnością optionala, pozwala na używanie null tam, gdzie go miało nie być, zamiast zwracania pustej wartości.

To jest cukier składniowy, który nie dodaje nic czego się nie da zrobić bez niego.

1

Ale jaką domyślna wartością? null to nie jest żadna wartość, to jest brak referencji.
Różnica taka jak między trzymaniem w ręce pustego portfela, a brakiem ręki.

Nigdzie nie napisałem, że domyślna wartość to null. Czy przypadkiem nie lepiej jest zwyczajnie ustawić ten obiekt żeby nie był null niż instalować paczkę z nugeta do tego? W mojej wypowiedzi chodziło mi o to, że nie trzeba żadnych monadów (nie wiem jak to się odmienia), aby uczulić się na null. W moim przykładzie z listą VS informuje o non-null i pomijając już uczepienie się tego co @Riddle cały powtarza, to pole "nie powinno" przyjmować null. Dodając opcje WarningToErrors błędy te jeszcze bardziej zwracają uwagę programisty, aby coś z tym zrobił. A robienie string s = null! to tylko robienie sobie krzywdy, bo owszem można tak napisać, ale co to rozwiązuje? Owszem udowadnia, że Microsoft podszedł do problemu jak mógł, albo nawet po łebkach, byleby było, ale jest zdecydowanie lepiej niż było. Tak zgadzam się, nie jest idealnie, ale jest lepiej ✌️

3
jarekr000000 napisał(a):

Pomijając, że java jest skopana, to jest akurat odwrotnie. Monady to normalka (jest ich troszkę więcej niż Optional).

Wiem i nie mam nic do monad ogółem, napisałem "te monady" w sensie Optional / Maybe. Nie wydaje mi się żeby java miała jakiekolwiek inne wbudowane.

jarekr000000 napisał(a):

A przykład, gdzie widać przewagę monad to np. Scala: (...)

Przewaga tego polega na tym, że niezależnie czy findUser() i kolejne zwraca Optional, Try, czy Either (zwane inaczej Result) a nawet Task/Future to kod pozostaje taki sam.

Nie pytałem o przewagę monad ogółem tylko w przytoczonych językach, zwłaszcza o c# o którym jest temat. Nie wątpię że w innych językach może to wyglądać inaczej, natomiast poprawcie mnie jeśli się mylę ale nie wydaje mi się żeby java czy c# mogły zachować ten sam kod po zmianie Optional na Future. W najlepszym przypadku zmienia się typ wyrażenia z IEnumerable na IAsyncEnumerable i trzeba dopisywać wszędzie await żeby to obsłużyć

somekind napisał(a):
AdamWox napisał(a):

W C# przecież jest nullable 🤔 po co komplikować projekt jakimiś bibliotekami?

nullable jest przecież całkowitą odwrotnością optionala, pozwala na używanie null tam, gdzie go miało nie być, zamiast zwracania pustej wartości.

Od wprowadzenia flagi nullable, T? nie jest już cukrem składniowym na Nullable<T> a niezależnym typem istniejącym na poziomie kompilacji dla typów referencyjnych.
Odwrotność czy nie, przechowuje te same informacje i odnosząc się do pytania w wątku nie ma sensu wprowadzać Optional / Either, można rozszerzyć (i to samemu) Nullable / T? / Result o "monadowe" funkcje do chainowania przykładowo odwzorowując artykuł z pierwszego posta:

static class NullableExt
{
    public static T? Some<T>(this T? that, Action<T> sth)
    {
        if (that is not null)
        {
            sth(that);
        }

        return that;
    }

    public static T? None<T>(this T? that, Action sth)
    {
        if (that is null)
        {
            sth();
        }

        return that;
    }
}

i wtedy jak komuś się podoba możemy sobie zamienić:

var user = getUser();
if (user != null)
{
  kill(user);
} else {
  Console.WriteLine("target lost");
}

na

getUser()
   .Some(kill)
   .None(() => Console.WriteLine("target lost"));
somekind napisał(a):

Proszę bardzo:

string s = null!;

Po wprowadzeniu słówek init i required nie ma żadnego racjonalnego uzasadnienia do używania wykrzykników poza używaniem przestarzałych bibliotek które wypadałoby zaktualizować.

Można sobie zainstalować reguły które nie pozwolą skompilować kodu z wykrzyknikami:
https://github.com/tom-englert/Nullable.Extended

1
obscurity napisał(a):

Wiem i nie mam nic do monad ogółem, napisałem "te monady" w sensie Optional / Maybe. Nie wydaje mi się żeby java miała jakiekolwiek inne wbudowane.

Zasadniczo java nie ma żadnych monad wbudowanych (i dobrze).
Biblioteka standardowa javy ma Optional, który zresztą nawet nie jest do końca monadą (bo zjezepsuta). Jest też CompletableFuture, które też jest zjezepsute :-)
(* jak jeszcze w javie pisałem - to obu nie używałem, bo jest biblioteka (vavr), która ma sensowne wersje Option, Either,Try(**), Future, Validation itd.)
(** żeby jeszcze zamącić to Try w vavr też jest zjezepsute - zaszłośc prehistoryczna)

A przykład, gdzie widać przewagę monad to np. Scala: (...)

Przewaga tego polega na tym, że niezależnie czy findUser() i kolejne zwraca Optional, Try, czy Either (zwane inaczej Result) a nawet Task/Future to kod pozostaje taki sam.

Nie pytałem o przewagę monad ogółem tylko w przytoczonych językach, zwłaszcza o c# o którym jest temat. Nie wątpię że w innych językach może to wyglądać inaczej, natomiast poprawcie mnie jeśli się mylę ale nie wydaje mi się żeby java czy c# mogły zachować ten sam kod po zmianie Optional na Future. W najlepszym przypadku zmienia się typ wyrażenia z IEnumerable na IAsyncEnumerable i trzeba dopisywać wszędzie await żeby to obsłużyć

Nie, nie trzeba. Spośród tony pojebanych ficzerów java jakimś cudem nie została obdarzona async/awaitem więc problemu nie ma.
W każdym przypadku masz flatMap ( ... flatMap ( flatMap(... )))) (pod warunkiem korzystania z odpowiedniego Future - bo ten w standardowej bibliotece javy to dramat).
(Strzelam, ale nie chce mi się tego sprawdzać(!!!), że w C# też nie musisz koniecznie korzystać z async/await to tylko opcja).

0
jarekr000000 napisał(a):

Spośród tony pojebanych ficzerów java jakimś cudem nie została obdarzona async/awaitem więc problemu nie ma.

Szczerze mówiąc, całe szczęście.

1
AdamWox napisał(a):

Nigdzie nie napisałem, że domyślna wartość to null. Czy przypadkiem nie lepiej jest zwyczajnie ustawić ten obiekt żeby nie był null niż instalować paczkę z nugeta do tego? W mojej wypowiedzi chodziło mi o to, że nie trzeba żadnych monadów (nie wiem jak to się odmienia), aby uczulić się na null. W moim przykładzie z listą VS informuje o non-null i pomijając już uczepienie się tego co @Riddle cały powtarza, to pole "nie powinno" przyjmować null. Dodając opcje WarningToErrors błędy te jeszcze bardziej zwracają uwagę programisty, aby coś z tym zrobił.

Tak, tylko że ustawienie obiektowi, żeby nie był null:

  1. nie działa w 100% przypadków;
  2. cieknie nam abstrakcja (albo raczej antyabstrakcja jaką jest null), bo używamy słowa kluczowego języka w celu, do którego nie zostało przeznaczone;
  3. z tego samego powodu, jest to zwyczajnie słaby design API, skoro używamy do modelowania procesu biznesowego literałów z języka;
  4. jest sprzeczne z silnym typowaniem;
  5. w końcu jebnie, bo gdzieś zapomnimy tego nulla sprawdzić.

A robienie string s = null! to tylko robienie sobie krzywdy, bo owszem można tak napisać, ale co to rozwiązuje?

Odpowiada na zadaną w wątku fałszywą tezę dotyczącą tego potężnego mechanizmu C# jakim jest NRT.

Owszem udowadnia, że Microsoft podszedł do problemu jak mógł, albo nawet po łebkach, byleby było, ale jest zdecydowanie lepiej niż było. Tak zgadzam się, nie jest idealnie, ale jest lepiej ✌️

Tak, jest lepiej niż było. Ale null to nadal brak referencji, a nie reprezentacja braku wartości.

obscurity napisał(a):

Odwrotność czy nie, przechowuje te same informacje

No własnie nie przechowuje tych samych, bo nie wiadomo, czy null trafił tam celowo czy przypadkiem.

Po wprowadzeniu słówek init i required nie ma żadnego racjonalnego uzasadnienia do używania wykrzykników

Nie wiem, czy kiedykolwiek było, no ale skoro cichą tezą tego wątku jest, że MS wszystko robi dobrze, to i wykrzykniki są dobre.

poza używaniem przestarzałych bibliotek które wypadałoby zaktualizować.

A kto za to zapłaci?
Kto zmusi twórców OS do aktualizacji kodu swoich bibliotek?

Można sobie zainstalować reguły które nie pozwolą skompilować kodu z wykrzyknikami:
https://github.com/tom-englert/Nullable.Extended

Czyli nie ma sensu instalować paczki do optionali, więc zainstalujmy paczkę do wykrzyników?
Trochę pokrętna logika.

0
jarekr000000 napisał(a):

Nie, nie trzeba. Spośród tony pojebanych ficzerów java jakimś cudem nie została obdarzona async/awaitem więc problemu nie ma.
W każdym przypadku masz flatMap ( ... flatMap ( flatMap(... )))) (pod warunkiem korzystania z odpowiedniego Future - bo ten w standardowej bibliotece javy to dramat).
(Strzelam, ale nie chce mi się tego sprawdzać(!!!), że w C# też nie musisz koniecznie korzystać z async/await to tylko opcja).

A, w ten sposób. No tak - trzymając się cały czas funkcyjnego stylu i monad można pisać w ten sposób, natomiast miałem na myśli łączenie to z istniejącym kodem i pisanie w ten sposób tylko w miejscach gdzie to faktycznie coś pomaga i powrót do imperatywnego kodu w kolejnych linijkach, a tego w łatwy sposób w javie się nie da uzyskać, a w c# wymaga małej zmiany kodu.
btw jednak wolę widzieć await ... await zamiast flatMap() flatMap()

Jasne, można pisać w javowy sposób w c#, natomiast nie po to się wybiera jakiś język żeby pisać w stylu innego języka.

W ogóle nie podoba mi się łączenie różnych styli pisania kodu, jeśli komuś bardziej podoba się taki styl to zamiast na siłę wciągać biblioteki tego typu do języka który był projektowany z całkiem inną ideą i robić protezy nie pasujące do reszty, moim zdaniem lepiej zmienić język.
Jeśli ktoś chce zostać z jakiegoś powodu w .NETowym środowisku to ma do dyspozycji F#, a tam może sobie korzystać z monad, discriminated unions i takich tam, poza tym tam zdaje się kwestia nulli też jest lekko lepiej rozwiązana bo "null" nie jest prawidłową wartością Nullable z tego co widzę. Natomiast w F# nie ma za dużo pracy więc nie polecam traktować tego poważnie (z drugiej strony w niczym już nie ma za dużo pracy więc co za różnica).
Po co z jednego języka nieudolnie robić inny?
Kiedy wejdziesz między wrony, rób tak, jak robią Rzymianie

1
obscurity napisał(a):

W ogóle nie podoba mi się łączenie różnych styli pisania kodu, jeśli komuś bardziej podoba się taki styl to zamiast na siłę wciągać biblioteki tego typu do języka który był projektowany z całkiem inną ideą i robić protezy nie pasujące do reszty, moim zdaniem lepiej zmienić język.
Jeśli ktoś chce zostać z jakiegoś powodu w .NETowym środowisku to ma do dyspozycji F#, a tam może sobie korzystać z monad, discriminated unions i takich tam, poza tym tam zdaje się kwestia nulli też jest lekko lepiej rozwiązana bo "null" nie jest prawidłową wartością Nullable z tego co widzę. Natomiast w F# nie ma za dużo pracy więc nie polecam traktować tego poważnie (z drugiej strony w niczym już nie ma za dużo pracy więc co za różnica).
Po co z jednego języka nieudolnie robić inny?
Kiedy wejdziesz między wrony, rób tak, jak robią Rzymianie

Niby do tego samego doszedłem, bo nie piszę już od dawna w javie, tylko w języku gdzie pisze się normalnie (scala/haskell).
Natomiast nie zgadzam się jednak do konca z argumentem "między wrony" - to jest bardziej "change the language or change the language".
Jeśli widzę, że mainstreamowy sposób pisania w danym jezyku (u mnie java) jest kulawy i błędogęnny (nulle, mutowanie itp). to jednak naginam ten styl do bardziej normalnego (czasem to nie ja do końca wybieram język). Zwłaszcza, że efekty pozytywne od razu widać. Fakt, powoduje to często "niespójność stylu" - ale pytanie czy warto mieć 100% spójny kijowy styl, czy choć w 10% dobry (mniej podatny na błędy, przeżywający refaktoring kod).

1
obscurity napisał(a):

Po co z jednego języka nieudolnie robić inny?

To jest właściwie bardzo dobre pytanie, które należałoby zadać twórcom C#.
Bo z jednej strony wskaźniki, stackallocki, parametry wyjściowe i null, a z drugiej jakieś funkcyjne mechanizmy i dziurawa kołdra na nulla.

1

@somekind

No faktycznie dziwne.

Ciekawe co oni sobie tam myślą, że ktoś C# używa do czegoś poza web devem? /s

1
WeiXiao napisał(a):

Ciekawe co oni sobie tam myślą, że ktoś C# używa do czegoś poza web devem? /s

Pytanie, czy jeśli język jest w 98% używany do webdevu, to musi mieć wskaźniki i goto.

0
somekind napisał(a):
WeiXiao napisał(a):

Ciekawe co oni sobie tam myślą, że ktoś C# używa do czegoś poza web devem? /s

Pytanie, czy jeśli język jest w 98% używany do webdevu, to musi mieć wskaźniki i goto.

Jeżeli te 2% sprawia że te 98% jako tako działa to tak

https://github.com/search?q=repo%3Adotnet%2Fruntime+"fixed+"&type=code

0
somekind napisał(a):

Pytanie, czy jeśli język jest w 98% używany do webdevu, to musi mieć wskaźniki i goto.

php ma goto więc chyba tak
nie wiem czy jest w 98% używany do webdevu (wątpię) ale zaczynał raczej głównie jako język desktopowy z winforms z możliwością kooperacji z kodem w c++, rozrósł się na webdev i gry, na pewno nie był tworzony z myślą o webdevie
A 2% to bardzo dużo, to tak jakbyś chciał olać wszystkich użytkowników linuksa na desktopach. A, czekaj...

0
WeiXiao napisał(a):

Jeżeli te 2% sprawia że te 98% jako tako działa to tak

https://github.com/search?q=repo%3Adotnet%2Fruntime+"fixed+"&type=code

Jest jakiś obowiązek pisania runtime języka X w języku X?

obscurity napisał(a):

php ma goto więc chyba tak
nie wiem czy jest w 98% używany do webdevu (wątpię) ale zaczynał raczej głównie jako język desktopowy z winforms z możliwością kooperacji z kodem w c++, rozrósł się na webdev i gry, na pewno nie był tworzony z myślą o webdevie

Był tworzony także z myślą o webdevie. ASP.NET pojawił się na świecie razem z WinFormsami.

A 2% to bardzo dużo, to tak jakbyś chciał olać wszystkich użytkowników linuksa na desktopach. A, czekaj...

Nie chcę nikogo olewać. Może istnieć więcej niż jeden język.

Pytanie, czy Wy na serio używacie argumentum ad traditionem w dyskusji?

0

Ja nie używam żadnego argumentum bo nawet nie jestem pewny o czym aktualnie jest ta dyskusja, natomiast jeśli rozmawiamy o tym dlaczego w języku jest goto i wskaźniki to myślę że warto się cofnąć czasami do momentu w którym zostały wprowadzone żeby wyjaśnić tę zagadkę.

somekind napisał(a):

Może istnieć więcej niż jeden język.

No i to jest właśnie to co pisałem wcześniej - nie kaleczyć języka Optionalami tylko zmienić język na taki który będzie ci pasował i nadawał lepiej do tego co robisz w sposób jaki to robisz. Jeśli masz z jakiegoś powodu problem z nullami bo może sam sobie strzelasz w kolano operatorem "null-forgiving" to zmień język na taki w którym ten problem został rozwiązany.
Osobiście:
a) zastrzeliłbym jakby mi ktoś do projektu wciągnął paczkę z Optional
b) nie pamiętam kiedy ostatnio miałem problem z nullem w C#, natomiast nadal w 2024 roku zdarzają się kolegom z zespołu w javie mimo że ich kod jest zaj**any optionalami bo ups - standardowe biblioteki nadal zwracają nulle i nic nie wymusza ich obsługi.

screenshot-20240321054431.png

Co jakiś czas musi powstać nowy język bo stare mają historyczne naleciałości których się nie da naprawić bez breaking changes i przestają pasować do obowiązujących standardów.
Ja C# do webdevu używam tylko w pracy, w 90% używam hobbistycznie i zacząłem od XNA, potem do WPF, UWP, background serwisów, Unity a potem MAUI (ostatniego nie polecam).

0
somekind napisał(a):
WeiXiao napisał(a):

Jeżeli te 2% sprawia że te 98% jako tako działa to tak

https://github.com/search?q=repo%3Adotnet%2Fruntime+"fixed+"&type=code

Jest jakiś obowiązek pisania runtime języka X w języku X?

Obowiązku nie ma, ale jest wiele zalet, tak samo jak przy pisaniu kompilatora języka X w języku X ;)

0
obscurity napisał(a):

Ja nie używam żadnego argumentum bo nawet nie jestem pewny o czym aktualnie jest ta dyskusja, natomiast jeśli rozmawiamy o tym dlaczego w języku jest goto i wskaźniki to myślę że warto się cofnąć czasami do momentu w którym zostały wprowadzone żeby wyjaśnić tę zagadkę.

Mhm, tylko warto też spojrzeć na to, czy czasem ewolucja języka nadąża za ewolucją jego użytkowania.

No i to jest właśnie to co pisałem wcześniej - nie kaleczyć języka Optionalami

W jaki niby sposób jest to kaleczenie?
Tworzenie własnych typów do przechowywania wartości to też kaleczenie?

b) nie pamiętam kiedy ostatnio miałem problem z nullem w C#, natomiast nadal w 2024 roku zdarzają się kolegom z zespołu w javie mimo że ich kod jest zaj**any optionalami bo ups - standardowe biblioteki nadal zwracają nulle i nic nie wymusza ich obsługi.

To gratuluję, tymczasem null wciąż jest problemem w C#, bo kod rzekomo nieakceptujący tej bezwartości może wciąż korzystać z bibliotek, które null zwracają. Jeśli ktoś nie daj borze uwierzy, że użycie NRT go przed czymś obroni, to wywali się jak krowa na wrotkach.

0
somekind napisał(a):

To gratuluję, tymczasem null wciąż jest problemem w C#, bo kod rzekomo nieakceptujący tej bezwartości może wciąż korzystać z bibliotek, które null zwracają. Jeśli ktoś nie daj borze uwierzy, że użycie NRT go przed czymś obroni, to wywali się jak krowa na wrotkach.

Nie kumam, jeśli korzystasz z jakiejkolwiek biblioteki która ma wyłączone nullable to wszystkie wartości z niej zwrócone będą widoczne jako nullable i jak zwróci nulla to będziesz musiał go obsłużyć (zakładając że masz włączone errory na nullable jak normalna osoba). Chyba że masz jakieś biblioteki które mają właczone nullable i mówią że zwracają nienullowalny typ a zwracają tam nulla no to zażalenia do autora takiej biblioteki ale nie zdarzyło mi się takiej używać.
Jak będziesz miał swój typ do przechowywania wartości to pustą wartość będziesz mógł obsłużyć tylko w tych miejscach w których wartość jest tym typem owrapowana.

0

Chodzi o to, że jak masz List<MyClass> myClasses { get; set; } to to w dalszym ciągu może przyjąć wartość NULL na przykład z API albo z SQLa. Aplikacja wysypie się na prostym myClasses.Count() albo myClasses.Where(), bo jest null. Jak dodasz ? to wtedy dopiero VS ciebie poinformuje o możliwym NULL w tym obiekcie.

0
AdamWox napisał(a):

Chodzi o to, że jak masz List<MyClass> myClasses { get; set; } to to w dalszym ciągu może przyjąć wartość NULL na przykład z API albo z SQLa. Aplikacja wysypie się na prostym myClasses.Count() albo myClasses.Where(), bo jest null. Jak dodasz ? to wtedy dopiero VS ciebie poinformuje o możliwym NULL w tym obiekcie.

Jeśli coś może przyjąć wartość null na przykład z deserializacji a tego nie masz zaznaczonego to masz tak naprawdę błędnie zdefiniowany kontrakt lub druga strona nie trzyma się tego kontraktu poprawnie i to jest najbardziej tricky part bo nic cię nie poinformuje o tym na etapie builda, trzeba samemu myśleć na etapie definiowania kontraktu i najbezpieczniej uznać że wszystkie wartości przyjmowane z zewnątrz zwłaszcza te od użytkownika mogą być nullem i wszędzie dać znaki zapytania i/lub walidować przychodzące dane. Nadal w tym przypadku Optional nie ma przewagi bo może się stać dokładnie to samo.

0

No nie, bo ja robię List<MyClass>, a nie List<MyClass>?, ja zakładam, że ta lista nigdy nie będzie null, a może być.

0
AdamWox napisał(a):

zakładam, że ta lista nigdy nie będzie null, a może być.

Słyszysz siebie 😉 ? Jeśli coś może być nullem to Twoim zadaniem jest to żeby zaznaczyć to ? (czytaj: może być nullem), a mogą być nullem wszystkie wartości pochodzące z niestabilnego źródła - deserializacji czy słabego api. Jeśli baza danych ma pole zaznaczone jako nullable a w Twoim kodzie nie jest nullable to też masz niespójność. To jest ta najtrudniejsza część na którą wszyscy narzekają - ten feature nie pozbywa się nullów, nadal trzeba myśleć, tylko że nie na etapie pisania logiki tylko na etapie definiowania typów.
Pokaż przykład którego nie opisuje mój poprzedni post (i w którym nie wsadzasz tego nulla na siłę wykrzyknikiem).

1

No ale to deserializacja - zgodnie ze sztuka - to sie winna jest wywalic jesli widzi nulla tam gdzie powinna byc obligatoryjnie wartosc. A jak juz masz instancje tej klasy to powinienes moc zalozyc, ze jest poprawna - przynajmniej jesli chodzi o typy

0
stivens napisał(a):

No ale to deserializacja - zgodnie ze sztuka - to sie winna jest wywalic jesli widzi nulla tam gdzie powinna byc obligatoryjnie wartosc. A jak juz masz instancje tej klasy to powinienes moc zalozyc, ze jest poprawna - przynajmniej jesli chodzi o typy

Po dodaniu słówka required deserializer się wywali jeśli będzie brakowało własności, ale nadal dopuści jeśli ktoś explicit wyśle nulla. No to jest jedna z lekko skopanych rzeczy które mogłyby być rozwiązane lepiej, nie rozumiem dlaczego wbudowany serializer nie ma opcji sprawdzania nullability.
Rozwiązań jest kilka ale nie o nich jest temat tylko o tym czy warto dodać monadę Option żeby zlikwidować tego typu błędy i po raz kolejny - nie, monada tu w niczym nie pomoże

0
obscurity napisał(a):

Nie kumam, jeśli korzystasz z jakiejkolwiek biblioteki która ma wyłączone nullable to wszystkie wartości z niej zwrócone będą widoczne jako nullable i jak zwróci nulla to będziesz musiał go obsłużyć

No i dlatego mówię, że to jest połowiczne rozwiązanie. Bo co z tego, że ja sobie napiszę swój cudowny kod, w którym na bank nie będzie NRE, skoro i tak będę musiał dopisać 3x więcej kodu na obsługę null z zewnątrz.

(zakładając że masz włączone errory na nullable jak normalna osoba).

Niezupełnie - po pierwsze nie każdy projekt, w którym biorę udział jest mój, więc nie wszędzie mogę sobie coś włączać, po drugie nie jest to kwestia normalności, a posiadanego czasu i zasobów na refaktoryzację kodu.

Jak będziesz miał swój typ do przechowywania wartości to pustą wartość będziesz mógł obsłużyć tylko w tych miejscach w których wartość jest tym typem owrapowana.

Dokładnie. A to tylko początek zalet stosowania silnego typowania.

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