Apa perbedaan antara jenis Opsional dan Nullable

15

Swift punya Optionals. C # memiliki Nullabletipe.

Sejauh yang saya tahu keduanya melayani tujuan yang sama, selain nilai beberapa jenis mereka menyimpan informasi apakah variabel memiliki nilai atau tidak didefinisikan (tidak diinisialisasi).

Pertanyaannya, apakah Optionalshanya Nullabletipe dengan nama yang berbeda atau ada perbedaan konseptual lainnya?

Dengan kata lain, berbicara tentang konsep itu sendiri, atau dalam konteks bahasa yang tidak memiliki Optionalsatau Nullables, apakah penting istilah mana yang digunakan?

Ketika menerapkan fungsionalitas itu dalam bahasa apakah masalah apakah saya nama tipe Optionals<T>atauNullable<T>

Dalija Prasnikar
sumber
Dari sudut pandang agnostik bahasa, mereka identik. Yang mengatakan, suatu bahasa dapat membedakan konsep (misalnya apakah pencocokan pola diberlakukan atau tidak).
Thomas Eding
C # dapat memiliki Opsi juga (itu hanya pola monadik): github.com/louthy/language-ext
Den
2
Menggunakan referensi nol (atau pointer NULL, dalam bahasa dengan pointer) adalah hack yang digunakan beberapa bahasa untuk mewakili nilai opsional, yaitu sebuah wadah yang mungkin memiliki satu nilai atau tidak ada nilai sama sekali. Ini memiliki batasan bahwa Anda hanya dapat mempertimbangkan jenis opsional yang didasarkan pada referensi (atau petunjuk). Jadi, misalnya, di Jawa Anda tidak dapat membuat bilangan bulat opsional tanpa membungkusnya dalam suatu objek (misalnya Bilangan Bulat). Bahasa lain menyediakan jenis opsional sebagai jenis umum yang dapat membungkus jenis lain, misalnya Mungkin di Haskell, Opsi dalam Scala, dan sebagainya.
Giorgio

Jawaban:

5

Ada konotasi yang berbeda, meskipun mereka bekerja sangat mirip. Semua orang kecuali Microsoft (masukkan eye-roll di sini) menggunakan nulldan nullablehanya dalam konteks referensi. Optionsdan Maybesumumnya dipahami merujuk pada referensi dan nilai, terutama dalam bahasa pemrograman fungsional di mana transparansi referensial berarti tidak ada banyak perbedaan antara nilai dan referensi.

Dengan kata lain, berbicara tentang konsep itu sendiri, atau dalam konteks bahasa yang tidak memiliki Optionalsatau Nullables, apakah penting istilah mana yang digunakan?

Optionsadalah istilah yang paling sedikit menyebabkan kebingungan di antara khalayak luas. Hanya pemrogram C # yang akan menganggap Nullableberpotensi menerapkan ke jenis nilai, dan saya pikir sebagian besar dari mereka setidaknya menyadari apa Optionitu.

Karl Bielefeldt
sumber
Semua orang kecuali Microsoft dan perancang SQL, saya pikir maksud Anda.
Jules
9

Dalam. NET, ada dua kategori tipe: referensi dan nilai (int, dobel, struct, enums dll). Di antara perbedaan mereka adalah fakta bahwa referensi bisa jadi null, sedangkan nilai tidak bisa. Jadi, jika Anda memiliki tipe nilai dan ingin menyampaikan semantik "opsional" atau "tidak dikenal", Anda dapat menghiasi itu Nullable<>. Catatan yang Nullable<>dibatasi oleh tipe untuk menerima hanya tipe nilai (memiliki where T : structklausa). Nullable<>juga memiliki harga khusus dari kompiler yang nullnilainya dilindungi dari NullReferenceExceptions:

string x = null;
x.ToString(); // throws a NullReferenceException

int? y = null;
y.ToString(); // returns ""

Dalam bahasa fungsional (seperti Scala, F #, Haskell, Swift dll) itu adalah umum untuk nulluntuk tidak ada . Ini karena secara keseluruhan orang menganggap keberadaan nullsebagai ide yang buruk , dan perancang bahasa telah memutuskan untuk mengatasi masalah ini dengan menolaknya.

Ini berarti bahwa sekali lagi kita perlu beberapa cara untuk mewakili nilai dalam bahasa ini. Masukkan Optiontipe (nomenklatur bervariasi, ini disebut Maybedalam Haskell). Ini melakukan pekerjaan yang mirip dengan Nullableyang membungkus jenis untuk menambahkan kasus di mana nilainya "Tidak Ada" atau "Tidak Diketahui" dll.

Perbedaan sebenarnya ada pada fungsi tambahan yang diberikan kepada Anda oleh bahasa yang menerapkan Option. Sebagai contoh, ambil Option.map(dalam pseudocode):

function Option<T2> Option.map(opt: Option<T1>, mapFunc: T1 -> T2) {
    if (opt is None) return None
    else return Option<T2>(mapFunc(opt.Value))
}

Fungsi perangkaian seperti Option.mapini adalah cara yang ampuh untuk menghindari pelat pelat nol yang biasa Anda lihat di mana-mana di C #:

if (service == null)
    return null;
var x = service.GetValue();
if (x == null || x.Property == null)
    return null;
return x.Property.Value;

Setara Nullable dalam C # adalah:

public static Nullable<T2> Map<T1, T2>(this Nullable<T1> nullable, Func<T1, T2> f)
    where T1 : struct
    where T2 : struct
{
    if (!nullable.HasValue) return (T2?)null;
    else return (T2?) f(nullable.Value);
}

Namun ini memiliki utilitas terbatas dalam C # karena hanya akan bekerja untuk tipe nilai.

Versi baru C # menawarkan operator "null propagation" ( ?.) yang mirip dengan Option.mapfungsi kecuali hanya berlaku untuk metode dan pengakses properti. Sampel di atas akan ditulis ulang

return service?.GetValue()?.Property?.Value;
AlexFoxGill
sumber
C # adalah bahasa fungsional yang tidak murni (seperti halnya F #). Juga F # memiliki nulls.
Den
C # 6 memiliki paksaan nilai nol, jadi setidaknya beberapa kode Anda tidak mutakhir: github.com/dotnet/roslyn/wiki/… roslyn.codeplex.com/discussions/540883
Den
Opsi juga mudah diterapkan: github.com/louthy/language-ext
Den
1
@Den: C # condong ke arah OOP sedangkan F # condong ke arah FP. Kurangnya currying dan mutability secara default berarti C # tidak sesuai untuk pemrograman fungsional yang serius. Saya menyebutkan propagasi nol di akhir jawaban. Opsi memang sederhana untuk diimplementasikan dalam C # tetapi itu menyimpang dari pertanyaan.
AlexFoxGill
4
@Den Saya pikir ada beberapa pilihan kata yang buruk dalam komentar Anda. Bahasa fungsional yang tidak murni adalah bahasa fungsional yang memungkinkan efek samping. C # mungkin memiliki beberapa fitur fungsional dan Anda dapat menggunakannya dengan sangat baik, tetapi ini bukan bahasa fungsional. Saya kira Anda maksudkan bahwa tidak ada bahasa yang 100% fungsional, tetapi F # sangat dekat dengan OCaml yang sebagian besar merupakan bahasa fungsional. Penyimpangan apa pun yang dibuatnya dari paradigma fungsional sebagian besar ada sehingga dapat beroperasi dengan kode .NET asing. Contoh kasus, nullbukan nilai yang valid untuk tipe F #.
Doval