Czy generalnie w C# stosuje się OPTIONAL<T> ?

Czy generalnie w C# stosuje się OPTIONAL<T> ?
JA
  • Rejestracja: dni
  • Ostatnio: dni
0

cześć
wiem, że język jako taki nie ma wbudowanego typu OPTIONAL (czy coś podobnego - mayby, some, none itd) ale czy Wy w swoich projektach używacie takiego czegoś czy po prostu null czeki?

Korci mnie optional, ale np jak taki typ jako zwrot z metody "wycieknie" z biblioteki - to znów zmuszamy kogoś kto korzysta z danej biblioteko do korzystania, tłumaczenia "naszego" optionala na nulle itd
a jak chcemy aby typ nie wyciekał, to i tak gdzieś w API musi być tłumaczenie OPTIONAL->(NULL lub TYP)

KamilAdam
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Silesia/Marki
  • Postów: 5550
0

Czy C# nie ma podobnie jak Kotlin typów z ? i bez ? właśnie po to żeby nie trzeba było stosować Optiona?
Jakiś czas temu w dziale Java byłą dyskusja na ten sam temat dla Kotlina. Czy lepsze jest Typ? czy Option<Typ?>.
Nie pamiętam do jakich wniosków doszli bo nie piszę ani w C#, a ani w Kotlinie oraz zawsze jak tylko mogę to wolę Optiona

mar-ek1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 526
3

Tak jak @KamilAdam wspomniał w C# są typy z ?. Do tej pory były używane do typów wartościowych, żeby też mogły być "puste". Ale jeżeli korzystasz z najnowszej wersji C# to możesz dawać ? też do typów referencyjnych i włączyć żeby kompilator pluł się za każdym razem jak chcesz ustawić null dla pola/właściwości, która nie jest oznaczona przez ?.
A używając tego operatora masz dostępne właściwości HasValue i Value. Więc w sumie to taki Optional wbudowny w język.

Azarien
  • Rejestracja: dni
  • Ostatnio: dni
4

@jakubek: > ##### jakubek napisał(a):

wiem, że język jako taki nie ma wbudowanego typu OPTIONAL (czy coś podobnego - mayby, some, none itd)

No to źle wiesz, bo jest Nullable<T>. Opisana wyżej przez kolegów składnia z ? jest lukrem składniowym na Nullable, ale można używać tego typu też bezpośrednio.

SW
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 250
0

Widziałem wewnętrzny projekt w C# w którym były próby przeforsowania Language extensions i wyszło na to, że generalnie ludzie woleli jednak pisać null checki ?. albo ?? niż mapować Optionale, w dodatku połączone z async/await. F# ma Option w bibliotece standardowej razem z async pattern matching, ale F# rzadko pojawia się w ofertach pracy.

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
2

Nullable<T> dla typów referencyjnych jest wymazywany (klasyczne type erasure) na etapie kompilacji (co teoretycznie niekoniecznie jest wadą, bo zależy co i jak zaimplementujemy). Jest (może) OK do oznaczania nullowalności, ale przy zabawach z typami już się wysypuje.

Mam lokalnie .NET 5.
Plik nullable.net.csproj:

Kopiuj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Plik Program.cs:

Kopiuj
using System;

public class Program
{
	class Option<T> {}
	
	static void Accept(Option<string> stringOption) {}

	// static void Accept(Nullable<string> nullableString) {} // doesn't compile
	
	static void AcceptOption<T>(Option<T> tOption) {}
	
	// static void AcceptNullable<T>(Nullable<T> nullableT) where T : notnull {} // doesn't compile
	
	static bool IsOfNullableType<T>(T o)
	{
		var type = typeof(T);
		return Nullable.GetUnderlyingType(type) != null;
	}
	
	public static void Main()
	{
		string hello1 = "Hello1";
		string? hello2 = "Hello2";		
		Console.WriteLine(IsOfNullableType(hello1)); // prints: False
		Console.WriteLine(IsOfNullableType(hello2)); // prints: False
	}
}

Coś mi te eksperymenty nie wychodzą.

PS: disclaimer - w C# piszę tylko jak chcę się ponapinać na forum.4p :P

JA
  • Rejestracja: dni
  • Ostatnio: dni
0

bardzo dziękuję za liczne odpowiedzi
może niedoprecyzowalem
dla mnie ? i ?? to generalnie null czeki - tak czy inaczej sprawdzają nulle

racziej chodziło mi o taki koncept jak RailwayProgramming, czyli (o ile dobrze rozumiem koncept) funkcyjny pomysł na C#

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
Azarien napisał(a):

No to źle wiesz, bo jest Nullable<T>.

Przecież Nullable to jest zupełnie coś innego niż Optional. :|

Opisana wyżej przez kolegów składnia z ? jest lukrem składniowym na Nullable, ale można używać tego typu też bezpośrednio.

Nie, nie jest.

Nullable służy do tego, aby umożliwić przypisanie null do zmiennej typu wartościowego, czyli takiego, który standardowo nie może nulla przechowywać. Celem jest więcej null w kodzie. Celem Optional jest pozbycie się nulli z kodu.

Przez Ciebie oranżadka w proszku znowu napisał kod, którego nie rozumie. Wstydź się!

jakubek napisał(a):

cześć

wiem, że język jako taki nie ma wbudowanego typu OPTIONAL (czy coś podobnego - mayby, some, none itd) ale czy Wy w swoich projektach używacie takiego czegoś czy po prostu null czeki?

Korci mnie optional, ale np jak taki typ jako zwrot z metody "wycieknie" z biblioteki - to znów zmuszamy kogoś kto korzysta z danej biblioteko do korzystania, tłumaczenia "naszego" optionala na nulle itd
a jak chcemy aby typ nie wyciekał, to i tak gdzieś w API musi być tłumaczenie OPTIONAL->(NULL lub TYP)

Gdyby móc polegać całkowicie na swoim kodzie, to byłoby fajnie, ale w praktyce zawsze trzeba się integrować z jakąś biblioteką czy serwisem, który może takiego nulla zwrócić. I tu powstaje ten problem, że połowa kodu może być piękna, a druga połowa i tak będzie wymagała tych null checków. No i ludzie raczej wybierają nulle wszędzie.

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
1
somekind napisał(a):

Nullable służy do tego, aby umożliwić przypisanie null do zmiennej typu wartościowego, czyli takiego, który standardowo nie może nulla przechowywać. Celem jest więcej null w kodzie. Celem Optional jest pozbycie się nulli z kodu.

Przez Ciebie oranżadka w proszku znowu napisał kod, którego nie rozumie. Wstydź się!

Przecież w C# 8 można zrobić Nullable<T> od typu referencyjnego (czyli takiego do którego można było przypisać nulla od zawsze), a więc liczba nulli w kodzie się od tego bezpośrednio nie zmieni: https://devblogs.microsoft.com/dotnet/embracing-nullable-reference-types/ Mój kod właśnie testował zachowanie nullable reference types (no chyba, że coś sknociłem).

AF
  • Rejestracja: dni
  • Ostatnio: dni
4

Nullable<T> w C# nie ma nic wspólnego z optionalem. Ponadto typy referencyjne z pytajnikiem nie mają nic wspólnego z Nullable. Ja nie wiem, kto tu Wibowitowi dał łapki w górę za jego wpis, ale to są niestety bzdury. Aczkolwiek podoba mi się, jak bez żadnego zastanowienia przeniósł przyzwyczajenia ze świata javowego do C# i wszystko pięknie mu pasowało Nullable<T> dla typów referencyjnych jest wymazywany (klasyczne type erasure) .

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
1
Afish napisał(a):

Aczkolwiek podoba mi się, jak bez żadnego zastanowienia przeniósł przyzwyczajenia ze świata javowego do C# i wszystko pięknie mu pasowało Nullable<T> dla typów referencyjnych jest wymazywany (klasyczne type erasure) .

Zanim to napisałem to poszukałem informacji i znalazłem takie coś: https://www.codejourney.net/2019/02/csharp-8-nullable-reference-types/#Nullable_reference_types_in_IL

Nullable reference types in IL
The only thing I found in the IL code compiled from source code with #nullable enabled directive was NullableAttribute applied to properties:
(obrazek)
It seems that nullable reference types are implemented by applying this attribute to variables, which is only used by the compiler (runtime is not affected).

AF
  • Rejestracja: dni
  • Ostatnio: dni
1
Wibowit napisał(a):

Zanim to napisałem to poszukałem informacji i znalazłem takie coś (...)

Nullable<T> i Nullable Reference Type są dwoma kompletnie różnymi rzeczami. To drugie nie jest typem, jest opcjonalnym atrybutem (javowym odpowiednikiem adnotacji) wstawianym przez kompilator. To nie jest typ, więc nie podlega wymazywaniu (pomijam już fakt, że generyki w dotnecie są reifikowane).

Twoje pomieszanie z poplątaniem wynika z faktu, że zacząłeś googlować "znany" termin i dostałeś wyniki, których nie da się zrozumieć w minutę bez znajomości reszty języka.

Poczytaj o Nullable<T> i po co to było, potem poczytaj o tym, jak to jest implementowane (i dlaczego nie da się zrobić własnego typu Nullable, a także dlaczego Nullable<string> nie działa tak, jak byś chciał). A na końcu zajrzyj na https://referencesource.microsoft.com/#mscorlib/system/nullable.cs,130 i zobacz, dlaczego Twój poprzedni kod (ten w poście wspominającym o wymazywaniu) działa tak czy inaczej.

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
1

Nullable<T> i Nullable Reference Type są dwoma kompletnie różnymi rzeczami. To drugie nie jest typem, jest opcjonalnym atrybutem (javowym odpowiednikiem adnotacji) wstawianym przez kompilator. To nie jest typ, więc nie podlega wymazywaniu (pomijam już fakt, że generyki w dotnecie są reifikowane).

Genericsy w Javie też działają jak adnotacja. Da się odczytać z pliku .class jakie są ograniczenia typów dla klasy czy składowych w klasie, ale z instancji klasy nie da się wyczytać nic dodatkowego (i na tym właśnie polega wymazywanie).

Twoje pomieszanie z poplątaniem wynika z faktu, że zacząłeś googlować "znany" termin i dostałeś wyniki, których nie da się zrozumieć w minutę bez znajomości reszty języka.

Racja. Pomyślałem, że Nullable<T> ma coś wspólnego z Nullable Reference Types (dziwne, że dodają nową rzecz zamiast zrobić jedną porządną). W sumie nawet jak się je połączy (jakkolwiek by to rozumieć) to i tak nie dostanie się pełni możliwości Optionala.

Rust zrobił Optionale ciekawie. Rustowy system typów zawiera takie pojęcie jak niezerowe typy, dla których można zrobić zoptymalizowaną reprezentację Optiona, np:
https://doc.rust-lang.org/std/num/struct.NonZeroU32.html

An integer that is known not to equal zero.
This enables some memory layout optimization. For example, Option<NonZeroU32> is the same size as u32:

Ta optymalizacja przenosi się to na referencje:
https://doc.rust-lang.org/std/option/index.html#options-and-pointers-nullable-pointers

This usage of Option to create safe nullable pointers is so common that Rust does special optimizations to make the representation of Option<Box<T>> a single pointer. Optional pointers in Rust are stored as efficiently as any other pointer type.

Niestety podwójny Option już rozwala optymalizację:

Kopiuj
use std::mem::size_of;

fn main() {
    assert_eq!(size_of::<Option<core::num::NonZeroU32>>(), size_of::<u32>()); // passes
    assert_eq!(size_of::<Option<Option<core::num::NonZeroU32>>>(), size_of::<u32>()); // fails
}

Z drugiej strony w C# i tak nie da się zrobić analogicznego string?? cokolwiek więc nawet by do takiej sytuacji nie doszło.

AF
  • Rejestracja: dni
  • Ostatnio: dni
0
Wibowit napisał(a):

Genericsy w Javie też działają jak adnotacja. Da się odczytać z pliku .class jakie są ograniczenia typów dla klasy czy składowych w klasie, ale z instancji klasy nie da się wyczytać nic dodatkowego.

Nie mierz dotneta miarą javy, bo to są dwie zupełnie inne rzeczy.

Wibowit napisał(a):

Racja. Pomyślałem, że Nullable<T> ma coś wspólnego z Nullable Reference Types (dziwne, że dodają nową rzecz zamiast zrobić jedną porządną). W sumie nawet jak się je połączy (jakkolwiek by to rozumieć) to i tak nie dostanie się pełni możliwości Optionala.

Najwyraźniej nie przeczytałeś, bo wtedy nie pisałbyś dziwne, że dodają nową rzecz zamiast zrobić jedną porządną

maszrum
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 219
0
somekind napisał(a):
Azarien napisał(a):

Opisana wyżej przez kolegów składnia z ? jest lukrem składniowym na Nullable, ale można używać tego typu też bezpośrednio.

Nie, nie jest.

A czy poprawne jest stwierdzenie, że T? jest lukrem składniowym dla Nullable<T>, ale tylko wtedy gdy T jest typem wartościowym?
W przeciwnym wypadku zostanie użyte nullable reference types, czyli wspomniana adnotacja.

Czy nieporozumienie wynika z tego, że T? działa inaczej dla typów wartościowych, a inaczej dla referencyjnych?

99xmarcin
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2420
0

W C# tradycyjnie nazywa się to Maybe<T> i osoby które starały się pisać funkcyjnie tego używały. Przykład: https://github.com/vkhorikov/CSharpFunctionalExtensions i moje własne przemyślenia z przed 2 lat: https://blog.marcinchwedczuk.pl/random-thoughts-on-maybe

Wydaje się że wraz z wprowadzeniem wsparcia ze strony kompilatora Maybe<T> odejdzie do lamusa (aczkolwiek pewnie wiele osób będzie i tak dodawać extension methods dla Filter i Map - bo często są wygodniejsze w użyciu).

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
Wibowit napisał(a):

Przecież w C# 8 można zrobić Nullable<T> od typu referencyjnego (czyli takiego do którego można było przypisać nulla od zawsze), a więc liczba nulli w kodzie się od tego bezpośrednio nie zmieni: https://devblogs.microsoft.com/dotnet/embracing-nullable-reference-types/ Mój kod właśnie testował zachowanie nullable reference types (no chyba, że coś sknociłem).

No nie można, bo definicja Nullable jest od 20 lat taka sama: public struct Nullable<T> where T : struct. struct sprawia, że nie użyjesz tam typu referencyjnego.
Ale fakt, użycie tej samej składni do dwóch różnych rzeczy jest strasznie pogmatwane, jak cały współczesny C# zresztą.

maszrum napisał(a):

A czy poprawne jest stwierdzenie, że T? jest lukrem składniowym dla Nullable<T>, ale tylko wtedy gdy T jest typem wartościowym?

Tak, jeśli T jest struct, to ? jest po prostu lukrem składniowym.

W przeciwnym wypadku zostanie użyte nullable reference types, czyli wspomniana adnotacja.

Ale typy referencyjne są przecież nullowalne od zawsze. :)
Samo dodanie ? do typu referencyjnego jest bezwartościowe. Gdy dodamy #nullable enable nadal będzie bezwartościowe. Dopiero gdy w takiej sytuacji napiszemy string z = null, to... w sumie wciąż będzie bezwartościowe, bo spowoduje jedynie ostrzeżenie kompilatora, na które i tak nikt nie spojrzy. ;)

Czy nieporozumienie wynika z tego, że T? działa inaczej dla typów wartościowych, a inaczej dla referencyjnych?

No jest to strasznie mylące, zwłaszcza jeśli ktoś nie siedzi w języku od n lat.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
2

@KamilAdam: @Wibowit

spokojnie Panowie, jeszcze 3 lata wojenek i będziecie mogli się przebranżowić na C# ;)

Wibowit
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: XML Hills
2
WeiXiao napisał(a):

spokojnie Panowie, jeszcze 3 lata wojenek i będziecie mogli się przebranżowić na C# ;)

A co się stanie przez te 3 lata? MS w końcu ogarnie typy wyższych rzędów? :]

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.