Boş referanslar gerçekten kötü bir şey midir?


161

Programlama dillerinde boş referansların bulunmasının "milyar dolarlık hata" olduğunu söylemiştim. Ama neden? Tabii, NullReferenceExceptions'e neden olabilirler, peki ne olmuş? Dilin herhangi bir unsuru, eğer yanlış kullanılırsa bir hata kaynağı olabilir.

Ve alternatif nedir? Sanırım bunu söylemek yerine:

Customer c = Customer.GetByLastName("Goodman"); // returns null if not found
if (c != null)
{
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Bunu söyleyebilirsin:

if (Customer.ExistsWithLastName("Goodman"))
{
    Customer c = Customer.GetByLastName("Goodman") // throws error if not found
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!"); 
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Ama bu nasıl daha iyi? Her iki durumda da, müşterinin varlığını kontrol etmeyi unutursanız, bir istisna elde edersiniz.

Bir CustomerNotFoundException'ın daha açıklayıcı olması nedeniyle NullReferenceException'dan hata ayıklamaktan biraz daha kolay olduğunu düşünüyorum. Hepsi bu kadar mı?


54
"Müşteri varsa / Müşteri kazanırsa" yaklaşımına karşı temkinli olurum, böyle iki kod satırı yazdığınızda, yarış koşulları için kapıyı açıyorsunuzdur. Alın ve sonra boş değerlerin olup olmadığını kontrol edin / istisnalar daha güvenlidir.
Carson63000,

26
Tüm çalışma zamanı hatalarının kaynağını ortadan kaldırabilirsek, kodumuzun mükemmel olacağı garanti edilir! C # içindeki NULL referansları beyninizi
kırarsa

bazı dillerde boş birleştirme ve güvenli navigasyon operatörleri olsa da
jk.

35
boş başına değil fena. T tipi ile T + null arasında fark yaratmayan bir tip sistemi kötüdür.
Ingo

27
Birkaç yıl sonra kendi soruma dönersek, şu anda tamamen Seçenek / Belki yaklaşımını değiştiriyorum.
Tim Goodman,

Yanıtlar:


91

null kötüdür

: Bu konu hakkında InfoQ bir sunum yoktur boş Referanslar: Milyar Dolar Hata tarafından Tony Hoare

Seçenek tipi

Fonksiyonel programlamanın alternatifi, ya da içerebilen bir Seçenek tipi kullanmaktır .SOME valueNONE

İyi bir makale Seçenek türünü tartışan ve bunun Java için uygulanmasını sağlayan “Seçenek” Deseni .

Ayrıca, bu konuda Java için bir hata raporu buldum: NullPointerExceptions özelliğini önlemek için Java'ya Güzel Seçenek türleri ekleyin . İstenen özellik Java 8'de tanıtıldı.


5
C # 'daki <x> null değeri benzer bir konsepttir, ancak seçenek modelinin bir uygulaması olmaktan çok az düşer. Bunun ana nedeni, .NET System.Nullable'ın değer türleriyle sınırlı olmasıdır.
MattDavey

27
+1 Seçenek tipi için. Haskell aşina aldıktan sonra Belki , nulls garip görünümlü başlamak ...
Andres F.

5
Geliştirici her yerde hata yapabilir, böylece boş işaretçi istisnası yerine boş seçenek istisnası alırsınız. İkincisi eskisinden daha iyi nasıl?
greenoldman

7
@greenoldman "boş seçenek istisna" diye bir şey yoktur. NULL değerleri NOT NULL olarak tanımlanan veritabanı sütunlarına eklemeyi deneyin.
Jonas,

36
@greenoldman Null değerindeki sorun, herhangi bir şeyin boş olabileceği ve geliştirici olarak ekstra temkinli olmanız gerektiğidir. Bir Stringtür gerçekten bir dize değil . Bu bir String or Nulltür. Seçenek türleri fikrine tamamen uyan diller, kendi tip sistemlerinde boş değerlere izin vermez ve bu, String(veya başka bir şey) gerektiren bir tür imzası tanımladığınızda değerinin olması gerektiğini garanti eder . OptionTip şeylerin bir tip düzeyinde temsilini sunmak için var ya da olmayabilir bir değere sahip, bu yüzden açıkça bu durumlarla başa gerekir nerede olduğunu biliyorum.
KChaloux

127

Sorun, teoride herhangi bir nesnenin boş olabileceği ve onu kullanmaya çalıştığınızda bir istisna atabileceği için, nesne yönelimli kodunuzun temelde patlamamış bombalar topluluğu olmasıdır.

Zarif hata işlemenin işlevsel olarak boş denetleme ififadeleriyle aynı olabileceği konusunda haklısınız . Fakat kendinizi ikna ettiğiniz bir şey muhtemelen boş olamazsa ne olur ? Kerboom. Sonra ne olursa olsun, bahse girerim ki 1) zarif olmayacak ve 2) hoşuna gitmeyecek.

Ve "hata ayıklaması kolay" değerini reddetmeyin. Olgun üretim kodu çılgınca, yayılan bir yaratıktır; neyin yanlış gittiği ve sizi saatlerce kazıdan kurtaracak yer hakkında daha fazla bilgi veren herhangi bir şey.


27
+1, genellikle üretim kodu hatalar ETMEK bunlar sabit olabilir bu nedenle mümkün olduğunca hızlı bir tespit (genellikle veri hatası) olması. Hata ayıklamak daha kolay, daha iyi.

4
OP'nin örneklerinden birine uygulanırsa, bu cevap aynıdır. Ya hata durumlarını test edersiniz, ya da yapmazsınız, ya da onları incelikle ele alırsınız ya da yapmazsınız. Başka bir deyişle, boş başvuruları dilden kaldırmak, yaşayacağınız hata sınıflarını değiştirmez, yalnızca bu hataların tezahürünü değiştirir.
dash-tom-bang

19
Patlamamış bombalar için +1. Boş referanslarla, public Foo doStuff()"şeyler yapmak ve Foo sonucunu döndürmek" demek, "şeyler yapmak ve Foo sonucunu iade etmek, VEYA null döndürmek anlamına gelmez, ancak bunun gerçekleşip gerçekleşmeyeceği hakkında hiçbir fikriniz yoktur" demek değildir. Sonuç olarak, emin olmak için HER YERİ boş bırakmanız gerekir. Boş değerlerin kaldırılması ve anlamsız bir değer belirtmek için özel bir tür veya desen (değer türü gibi) kullanın.
Matt Olenik

12
@greenoldman, örneğiniz anlamsal modeller olarak ilkel türlerin (null veya tamsayılar) kullanılmasının kötü bir uygulama olduğunu göstermemizde iki kat etkilidir. Negatif sayıların geçerli bir cevap olmadığı bir türünüz varsa, semantik modeli bu şekilde uygulamak için yeni bir tür sınıf oluşturmalısınız. Şimdi bu negatif olmayan tipin modellenmesi ile ilgili tüm kodlar sınıfına yerelleştirilir, sistemin geri kalanından izole edilir ve bunun için negatif bir değer yaratma girişimi hemen yakalanabilir.
Huperniketes

9
@greenoldman, ilkel türlerin modelleme için yetersiz olduğu noktasını kanıtlamaya devam edersiniz. İlk önce negatif sayılar üzerindeydi. Sıfır bölen olduğunda şimdi bölme operatörünün bitti. Sıfırla bölemeyeceğinizi biliyorsanız , sonucun güzel olmayacağını tahmin edebilirsiniz ve test etmenizi sağlamaktan ve bu dava için uygun "geçerli" değeri sağlamaktan sorumludur. Yazılım geliştiriciler, kodlarının çalıştığı parametreleri bilmek ve uygun şekilde kodlamaktan sorumludur. Bu, mühendisliği tamir etmekten ayırt eden şeydir.
Huperniketes

50

Kodda boş referanslar kullanmanın çeşitli problemleri vardır.

İlk olarak, genellikle özel bir durumu belirtmek için kullanılır . Uzmanlıklar normal olarak yapılırken her bir durum için yeni bir sınıf veya sabit tanımlamak yerine, boş bir referans kullanarak, kayıplı, kitlesel bir genelleştirilmiş tip / değer kullanılır .

İkincisi, null bir başvuru göründüğünde hata ayıklama kodu daha zor hale gelir ve neyi oluşturduğunu , hangi durumun geçerli olduğunu ve nedenini yukarı yöndeki yürütme yolunu izleyebilseniz bile nedenini belirlemeye çalıştığınızda zorlaşır .

Üçüncü olarak, boş referanslar test etmek için ek kod yolları sunar .

Dördüncüsü, boş referanslar parametrelerin yanı sıra dönüş değerleri için geçerli durumlar olarak kullanıldığında, savunma programlaması (tasarımın neden olduğu durumlar için) , çeşitli durumlarda yapılacak daha boş referans kontrolü gerektirir …

Beşinci olarak, dilin çalışma zamanı zaten bir nesnenin yöntem tablosunda seçici arama gerçekleştirdiğinde tür denetimleri gerçekleştiriyor. Dolayısıyla, nesnenin türünün geçerli / geçersiz olup olmadığını kontrol ederek ve ardından çalışma zamanının yöntemini çağırmak için geçerli nesnenin türünü kontrol etmesini sağlayarak çabaları çoğaltırsınız.

Neden kullanmayın NullObject deseni için çalışma zamanının kontrol yararlanmak bunu çağırmak için NOP sizin kod temeli boyunca da boş referanslar için tüm ekstra denetimi ortadan kaldırırken o halde (normal devletin arabirimine uygun) özel yöntemler?

Bu daha çok işe neden özel bir durumu temsil istediğiniz her arayüz için bir NullObject sınıfını oluşturarak. Ancak en azından uzmanlık, devletin var olabileceği koddan ziyade her bir özel duruma izole edilir. Şimdi, yöntemlerinde daha az alternatif yürütme yoluna sahip olduğunuz için test sayısı azalır .


7
... çünkü sözde faydalı nesneyi dolduran çöp verilerini kimin ürettiğini (veya daha doğrusu değiştirmeyi veya başlatmayı zahmet etmedi) bulmak NULL referansı takip etmekten çok daha kolaydır? Statik olarak yazılmış bir arazide sıkışıp kalmama rağmen, satın almıyorum.
dash-tom-bang

Çöp verileri, boş referanslardan çok daha nadirdir. Özellikle yönetilen dillerde.
Dean Harding,

5
Boş Nesne için -1.
DeadMG

4
Puan (4) ve (5) sağlam, ancak NullObject bir çare değil. Daha da kötüsü tuzak - mantık (iş akışı) hatalarına düşeceksiniz. Tam olarak bildiğiniz zaman, şu anki durum, elbette, yardımcı olabilir, ama bunu kör olarak kullanmak (null yerine) size daha fazla mal olacak.
greenoldman

1
@ gnasher729, Objective-C'nin çalışma zamanı Java ve diğer sistemler gibi bir boş gösterici istisnası oluşturmazken, cevabımda belirttiğim nedenlerle boş referansları kullanmayı daha iyi yapmaz. Örneğin [self.navigationController.presentingViewController dismissViewControllerAnimated: YES completion: nil];, çalışma zamanında herhangi bir navigasyon kontrolörü yoksa , bunu çalışmayanlar dizisi olarak görür, görünüm ekrandan kaldırılmaz ve nedenini anlamaya çalışırken saatlerce kafanızı tırmalamak için Xcode'un önünde oturabilirsiniz.
Huperniketes

48

Null'lar o kadar da kötü değil, beklemiyorsanız. Sen gerektiğini açıkça dile tasarım sorunudur null bekliyorsanız kodu belirtmek gerekir. Bunu düşün:

Customer? c = Customer.GetByLastName("Goodman");
// note the question mark -- 'c' is either a Customer or null
if (c != null)
{
    // c is not null, therefore its type in this block is
    // now 'Customer' instead of 'Customer?'
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

A yöntemlerini çağırmaya çalışırsanız Customer?, derleme zamanı hatası almalısınız. Daha fazla dilin bunu yapmamasının nedeni (IMO), hangi kapsamda olduğuna bağlı olarak değişmek üzere bir değişkenin türünü sağlamamış olmalarıdır. tip sistemi

Opsiyon tiplerini kullanarak bu problemi çözmenin fonksiyonel bir yolu da var Maybe, ama ben o kadar aşina değilim. Bu yolu tercih ederim, çünkü doğru kod teorik olarak doğru bir şekilde derlemek için sadece bir karaktere ihtiyaç duymalıdır.


11
Vay, çok güzel. Derleme sırasında çok fazla hata yakalamak için ek olarak, olmadığını anlamaya belgeleri kontrol etmek zorunda beni yedek GetByLastNameDöndürdüğü mı diye görebiliyorum - bulunmazsa eğer (bir istisna atma yerine) döndürür sıfır Customer?veya Customer.
Tim Goodman

14
@JBRWilkinson: Bu, fikri göstermek için gerçek bir uygulama örneği değil, sadece pişirilmiş bir örnektir. Aslında çok güzel bir fikir olduğunu düşünüyorum.
Dean Harding

1
Yine de boş nesne kalıbı olmadığı konusunda haklısın.
Dean Harding

13
Bu Haskell'in söylediği şeye benziyor Maybe- A Maybe Customerya Just c(nerede ca Customer) ya da Nothing. Diğer dillerde, denir Option- bu sorudaki diğer cevapların bazılarına bakınız.
MatrixFrog

2
@SimonBarker: Eğer yapabilirsiniz emin olun Customer.FirstNametiptedir String(aksine String?). Asıl fayda budur - yalnızca anlamlı hiçbir değeri olmayan değişkenler / özellikler null olarak nitelendirilmelidir.
Yogu

20

Talihsiz semptomlarını kapsayan birçok mükemmel cevap var null, bu yüzden alternatif bir argüman sunmak istiyorum: Null, tip sistemindeki bir kusurdur.

Bir tip sistemin amacı, bir programın farklı bileşenlerinin "birbirine tam olarak uyması"; iyi yazılmış bir program tanımsız davranışa “raylardan” kaçamaz.

Varsayımsal bir Java lehçesi düşünün ya da tercih ettiğiniz statik olarak yazılmış dil ne olursa olsun, dizeyi "Hello, world!"herhangi bir değişkene atayabilirsiniz :

Foo foo1 = new Foo();  // Legal
Foo foo2 = "Hello, world!"; // Also legal
Foo foo3 = "Bonjour!"; // Not legal - only "Hello, world!" is allowed

Ve bunun gibi değişkenleri de kontrol edebilirsiniz:

if (foo1 != "Hello, world!") {
    bar(foo1);
} else {
    baz();
}

Bunun imkansız bir tarafı yok - isterlerse biri böyle bir dil tasarlayabilir. Özel değerin olması gerekmez "Hello, world!"- 42 sayısı, sayı (1, 4, 9)ya da diyelim ki null. Ama bunu neden yaptın? Bir tür değişkeni Foosadece Foos tutacaktır - bu, tip sisteminin bütün noktası budur! nullolduğundan Foodaha fazla değil "Hello, world!". Daha da kötüsü, hiçbir türden nullbir değer değildir ve bununla yapabileceğiniz hiçbir şey yoktur!

Programcı bir değişkenin gerçekte bir a değerine sahip olduğundan asla emin Fooolamaz ve programın da yapamaz; tanımsız davranışlardan kaçınmak için değişkenleri s "Hello, world!"olarak kullanmadan önce kontrol etmek zorundadır Foo. Önceki kod parçasında dize denetimi yapmanın, foo1'in gerçekten bir Foo- olduğu gerçeğini yaymadığını - barbüyük olasılıkla kendi güvenliğini sağlamak için muhtemelen kendi denetimine sahip olacağını unutmayın.

Bunu, kalıp eşleştirme ile bir Maybe/ Optiontype kullanarak karşılaştırın :

case maybeFoo of
 |  Just foo => bar(foo)
 |  Nothing => baz()

İçinde Just foomaddesi, sen ve programın hem Emin bizim bu Maybe Foodeğişken gerçekten bir içermiyor Foodeğeri - bu bilgiler çağrı zincirini aşağı yayılır ve barherhangi denetimlerini yapmak gerekmez. Maybe FooFarklı bir tür olduğundan , Fooiçerme olasılığını ele almak zorunda Nothingkalırsınız, böylece asla a tarafından kör göremezsiniz NullPointerException. Programınız hakkında çok daha kolay bir neden olabilir ve derleyici, türün tüm değişkenlerinin Foogerçekten Foos içerdiğini bilerek boş denetimlerden kaçınabilir . Herkes kazanır.


Perl 6'daki boş değerlere ne dersiniz? Hala boşlar, her zaman yazılmaları dışında. Hala yazabileceğiniz bir sorun mu , türün boş değeri my Int $variable = Intnerede ? IntInt
Konrad Borowski

@xfix Ben Perl aşina değilim, ama sürece zorlama bir yolu yok gibi this type only contains integersaksine this type contains integers and this other value, bir sorunu her zaman var olacak tek tamsayılar istiyorum.
Doval,

1
Desen eşlemesi için +1. Yukarıdaki Seçenek türlerinden bahseden cevapların sayısında, birisinin örüntü eşleştiriciler gibi basit bir dil özelliğinin onları çalışmamak için boş alanlardan çok daha sezgisel hale getirebileceğinden bahsetmiş olacağını düşünebilirsiniz.
Jules

1
Monadik bağlamanın kalıp eşleştirmeden bile daha yararlı olduğunu düşünüyorum (elbette belki kalıp eşleştirmeyi kullanarak da uygulanmış olsa da). Bunun şeylerin (bolca özel sözdizimi koyarak tür C # gibi eğlenceli görerek dilleri olduğunu düşünüyorum ??, ?.Haskell gibi diller olarak kütüphane işlevleri yerine şeyler için, ve benzeri). Bence çok daha temiz. null/ Nothingpropagasyon hiçbir şekilde "özel" değildir, öyleyse neden buna sahip olmak için daha fazla sözdizimi öğrenmek zorundayız?
sara

14

(Eski bir soru için şapkamı ringe fırlatmak;)

Null ile ilgili özel sorun statik yazmayı bozmasıdır.

Eğer varsa Thing t, derleyici arayabileceğimi garanti edebilir t.doSomething(). Eh, UNLESS tçalışma zamanında boş. Şimdi tüm bahisler kapalı. Derleyici tamam dedi, ama taslında daha sonra olmadığını biliyorum doSomething(). Öyleyse, yazıcının hatalarını yakalamak için derleyiciye güvenmek yerine, onları yakalamak için çalışma zamanına kadar beklemeliyim. Python'u da kullanabilirim!

Bu nedenle, bir anlamda null, beklenen sonuçları içeren, statik olarak yazılmış bir sisteme dinamik yazmayı sağlar.

Bu sıfıra veya negatif log'a vb. Göre olan fark, i = 0 olduğunda, hala bir int'dir. Derleyici türünü hala garanti edebilir. Sorun, mantığın bu değeri, mantığın izin vermeyeceği bir şekilde yanlış uygulamasıdır ... ama mantık bunu yaparsa, bu hemen hemen bir hatanın tanımıdır.

(Derleyici olabilir gibi ifadeler işaretleme gibi. BTW, bu sorunlardan bazılarını yakalamak i = 1 / 0derleme zamanında. Ama gerçekten derleyici bir işlev haline takip etmek ve parametreler tüm işlevin mantığı ile tutarlı olmasını sağlamak için bekleyemeyiz)

Pratik sorun, fazladan fazla iş yapmanız ve çalışma zamanında kendinizi korumak için boş kontroller eklemenizdir, peki ya bir tanesini unutursanız? Derleyici atamalarını engeller:

S = s = yeni Tamsayı (1234);

Öyleyse neden referansları kıracak bir değere (boş) atanmasına izin vermelidir s?

Kodunuzda "yazılmamış" referanslarla "değer yok" ifadesini karıştırarak, programcılara fazladan bir yük getirmiş olursunuz. Ve NullPointerExceptions gerçekleştiğinde, onları izlemek daha da zaman alabilir. Aksine "Bunu söylemek statik yazarak güvenmek yerine ise dil demek alırız beklenen şey bir referans" "Bu iyi olabilir beklenen şey bir başvuru."


3
C'de, bir tür değişkeni *intbir intya da NULL. Benzer şekilde C ++, tipte bir değişken *Widgetya tanımlar Widget, türü bir şey türeyen Widgetveya NULL. Java ve C # gibi türevleri ile ilgili sorun, depolama konumunu Widgetortalama olarak kullanmalarıdır *Widget. Çözüm, *Widgettutmayacak gibi davranmak değil NULL, uygun bir Widgetdepolama yeri türüne sahip olmaktır .
supercat

14

Bir nullişaretçi bir araçtır

bir düşman değil. Onları doğru kullanmalısın.

Boş bir işaretçi hatasını bulma ve düzeltmeye kıyasla, tipik bir geçersiz işaretçi hatasını bulmanın ve gidermenin ne kadar zaman alacağını bir dakika düşünün . Bir işaretçiyi aleyhine kontrol etmek kolaydır null. Boş olmayan bir göstergenin geçerli verileri gösterip göstermediğini doğrulamak bir PITA'dır.

Hala ikna olmadıysanız, senaryoya çok miktarda okuyuculu ekleyin ve tekrar düşünün.

Hikayenin ahlaki: Çocukları suyla atma. Ve kazanın araçlarını suçlama. Sayıyı uzun zaman önce icat eden adam oldukça zekiydi, o günden beri "hiçbir şey" olarak adlandırabiliyordunuz. nullİşaretçi şimdiye kadar bunlardan uzak değildir.


EDIT: Her ne kadar NullObjectdesen boş olabilecek referanslardan daha iyi bir çözüm gibi görünse de, problemleri kendi kendine ortaya koymaktadır:

  • Bir NullObjectyöntem tutan bir referans (teoriye göre) tutan bir şey çağrıldığında hiçbir şey yapmaz. Bu nedenle, artık boş olmayan (yehaa!) Olduğu garanti edilen, ancak istenmeyen bir eylem gerçekleştirdiği, hatalı şekilde atanmamış referanslar nedeniyle ince hatalar ortaya çıkabilir. Bir NPE ile sorunun nerede olduğu açıkça bellidir. Bunun bir NullObjectşekilde (ancak yanlış) davranmasıyla, geç fark edilen hataların da görülmesi riski vardır. Bu, kazara geçersiz bir işaretçi sorununa benzer değildir ve benzer sonuçları doğurur: Referans, geçerli veriler gibi görünen, ancak görünmeyen, veri hatalarına neden olan ve izlenmesi zor olabilen bir şeye işaret eder. Dürüst olmak gerekirse, bu durumlarda göz açıp kapayıncaya kadar hemen başarısız olan bir NPE'yi tercih ederim.birden bire bana yolun aşağısında çarptığım bir mantıksal / veri hatası üzerinden. IBM'in hataların maliyeti konusunda hangi aşamada tespit edildiğinin bir işlevi olduğunu hatırlayın?

  • Bir yöntem çağrıldığında hiçbir şey yapmama kavramı, NullObjectbir özellik alıcısı veya bir işlev çağrıldığında veya yöntem, değerleri döndürdüğünde geçerli olmaz out. Diyelim ki, geri dönüş değeri birdir intve biz karar veriyoruz, "hiçbir şey yapmamak" ın "geri dönüş 0" anlamına geliyor. Ancak, 0'ın, döndürülecek (döndürülmemiş) doğru "hiçbir şey" olmadığından nasıl emin olabiliriz? Sonuçta, NullObjecthiçbir şey yapmamalı, ancak bir değer istendiğinde bir şekilde tepki vermesi gerekir. Başarısızlık bir seçenek değildir: NullObjectNPE'yi önlemek için onu kullanırız ve kesinlikle başka bir istisnaya karşı işlem yapmayız (uygulanmadı, sıfıra böl, ...), değil mi? Öyleyse, bir şeyi iade etmek zorunda kaldığında hiçbir şeyi doğru bir şekilde nasıl geri veremezsin?

Yardım edemem, ancak birileri NullObjecther bir problem için deseni uygulamaya çalıştığında, bir hatayı bir diğerini yaparak düzeltmeye çalışmak gibi görünüyor. Hiç şüphesiz bazı durumlarda iyi ve kullanışlı bir çözümdür , ancak kesinlikle tüm durumlar için sihirli mermi değildir.


Neden nullolması gerektiğine dair bir argüman sunabilir misin ? Herhangi bir dilin kusuru hakkında "bir sorun değil, sadece bir hata yapmayın" ifadesiyle elde etmek mümkün.
Doval

Hangi değere geçersiz bir işaretçi koyarsınız?
JensG

Onları hiçbir değere ayarlamazsınız, çünkü onlara hiç izin vermemelisiniz. Bunun yerine, belki de Maybe Tya Nothingda bir Tdeğer içerebilen denilen farklı türde bir değişken kullanırsınız . Buradaki en önemli şey , kullanmanıza izin verilmeden önce bir Maybegerçekten içerip içermediğini kontrol Tetmeniz ve kullanmamanız durumunda bir eylem kursu sağlamanız gerektiğidir. Geçersiz işaretçilere izin vermediğiniz için, şimdi hiç olmayan bir şeyi kontrol etmeniz gerekmez Maybe.
Doval

1
En son örneğinizdeki @JensG, derleyici her çağrıdan önce boş kontrol yapmanıza neden olur t.Something()mu? Yoksa daha önce kontrol ettiğinizi bilmenizi ve bir daha yapmamızı sağlamanın bir yolu var mı? Ya tbu metoda geçmeden önce kontrolü yaptıysanız ? Seçenek türüyle, derleyici, denetimi türüne bakarak henüz yapıp yapmadığınızı bilir t. Bu bir Seçenek ise kontrol etmediniz, oysa açılmamış değer ise o zaman elinizde.
Tim Goodman,

1
Bir değer istendiğinde nesneyi null döndürürsünüz?
JensG

8

Boş referanslar bir hatadır çünkü duyusal olmayan koda izin verirler:

foo = null
foo.bar()

Tip sisteminden yararlanıyorsanız, alternatifler var:

Maybe<Foo> foo = null
foo.bar() // error{Maybe<Foo> does not have any bar method}

Genel fikir, değişkeni bir kutuya koymaktır ve yapabileceğiniz tek şey, kutuyu açmaktır, tercihen Eiffel için önerilen derleyici yardımını sağlamaktır.

Haskell scratch ( Maybe) 'e sahiptir, C ++' da kaldıraç kullanabilirsiniz boost::optional<T>ancak hala tanımsız davranışlar alabilirsiniz ...


6
"Kaldıraç" için -1!
Mark C,

8
Fakat kesinlikle çok sayıda ortak programlama yapısı saçma kodlara izin veriyor, değil mi? Sıfırla bölme (tartışmalı) saçmadır, ancak yine de bölmeye izin veririz ve programcının bölenin sıfır olmadığını kontrol etmeyi (veya istisnayı ele almayı) hatırlamasını umarız.
Tim Goodman

3
Sana "sıfırdan" ile ne demek emin değilim ama Maybeçekirdek diline dahili olmayan, tanımı sadece standart başlangıcı olması umulur: data Maybe t = Nothing | Just t.
fredoverflow

4
@FredOverflow: başlangıç ​​varsayılan olarak yüklendiğinden, Haskell'in bu genel dilin kuralları ile tanımlanmasına izin vermek için (ve diğer) nişanların sadece bir bonus olduğunu düşünecek kadar şaşırtıcı türde bir sistemi olduğunu düşünürdüm. :)
Matthieu M.

2
@TimGoodman Sıfırla bölme, tüm sayısal değer türleri için en iyi örnek olmasa da (IEEE 754, sıfır türüne bölünme sonucunu tanımlar), istisna atacağı durumlarda, türün değerlerinin türün Tdiğer değerlerine bölünmesi yerine T, işlemi tür Tdeğerlerine bölünmüş tür değerleriyle sınırlandırırsınız NonZero<T>.
kbolino

8

Ve alternatif nedir?

İsteğe bağlı türler ve örüntü eşleme. C # bilmediğimden, burada Scala # :-) adlı kurgusal bir dilde bir kod parçası

Customer.GetByLastName("Goodman")    // returns Option[Customer]
match
{
    case Some(customer) =>
    Console.WriteLine(customer.FirstName + " " + customer.LastName + " is awesome!");

    case None =>
    Console.WriteLine("There was no customer named Goodman.  How lame!");
}

6

Boşluklarla ilgili sorun, onların sizi savunmaya karşı savunmaya zorlamalarına izin veren dillerdir. Bunu sağlamak için çok çaba sarf etmek (savunma if-blokları kullanmaya çalışmaktan çok daha fazla)

  1. Onları boş bırakmamalarını beklediğiniz nesneler gerçekten boş değildir ve
  2. Savunma mekanizmalarının gerçekten de tüm potansiyel NPE'lerle etkin bir şekilde başa çıkması.

Yani, aslında, nulllar sahip olmak için pahalı bir şey olur.


1
Boşluklarla baş etmek için daha fazla çaba harcayan bir örnek eklediyseniz yararlı olabilir. Kuşkusuz aşırı basitleştirilmiş örneğimde, çaba aynı şekilde. Seninle aynı fikirde değilim, sadece özel (sözde) kod örnekleri buluyorum genel ifadelerden daha net bir resim çiziyorum.
Tim Goodman

2
Ah, kendimi açıkça açıklamadım. Boş değerlerle baş etmek daha zor değil. Potansiyel olarak boş olan referanslara tüm erişimin zaten güvenli bir şekilde korunmasını garanti altına almak (imkansız değilse de) son derece güçtür . Başka bir deyişle, boş referanslara izin veren bir dilde, herhangi bir büyük boyutta zorluk ve çaba sarf etmeden, rastgele büyüklükte bir kod parçasının boş gösterici istisnalarından arınmış olduğunu garanti etmek imkansızdır. Boş referansları pahalı bir şey yapan budur. Boş gösterici istisnalarının tamamen yokluğunu garanti etmek son derece pahalıdır.
luis.espinal,

4

Programlama dilinizin, programınızın başlamadan önce programın doğruluğunu kanıtlamaya çalıştığı sorun. Statik olarak yazılmış bir dilde doğru tiplere sahip olduğunuzu kanıtladınız. Null olmayan referansların varsayılanına (isteğe bağlı null referansları ile) geçerek, null'un geçtiği ve olmaması gereken birçok durumu ortadan kaldırabilirsiniz. Sorun, geri çevrilemez referansları kullanma konusundaki ekstra çabanın programın doğruluğu bakımından yararına olup olmadığıdır.


4

Sorun o kadar boş değil, pek çok modern dilde boş olmayan bir başvuru türü belirtemezsiniz.

Örneğin, kodunuz benziyor olabilir

public void MakeCake(Egg egg, Flour flour, Milk milk)
{
    if (egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    egg.Crack();
    MixingBowl.Mix(egg, flour, milk);
    // etc
}

// inside Mixing bowl class
public void Mix(Egg egg, Flour flour, Milk milk)
{
    if (egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    //... etc
}

Sınıf referansları etrafından geçtiğinde, savunma programlaması, tüm parametreleri önceden null için kontrol etseniz bile, özellikle test altında yeniden kullanılabilir birimler oluştururken bile, null için tüm parametreleri kontrol etmenizi teşvik eder. Aynı referans, kod temeli üzerinden 10 kez kolayca kontrol edilebilir!

Bir şey aldığınızda normal bir null türüne sahip olmanız, null ile o zaman ve oraya gitmeniz daha iyi olmaz mıydı? zaman?

Bu, Seçenek çözümünün amacı - hata durumlarını açmanıza izin vermek değil, boş argümanları tam olarak kabul edemeyen işlevlerin tasarımına izin vermek. "Varsayılan" türlerin uygulanmasının null veya null olmayan olması, her iki aracın da kullanılabilmesi esnekliğinden daha az önemlidir.

http://twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing-the-billion-dollar-mistake

Bu aynı zamanda C # -> https://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c için en çok oy alan 2. özellik olarak listelenmiştir.


Seçenek <T> ile ilgili bir diğer önemli nokta, bunun bir monad (ve dolayısıyla bir endofunctor) olmasıdır, böylece Noneyolun her bir adımını açıkça kontrol etmeden isteğe bağlı türler içeren değer akışları üzerinde karmaşık hesaplamalar oluşturabilirsiniz .
sara,

3

Null kötüdür. Bununla birlikte, boş bir eksikliği daha büyük bir kötülük olabilir.

Sorun şu ki, gerçek dünyada çoğu zaman verilerinizin olmadığı bir durum var. Boş değer içermeyen versiyon örneğiniz hala patlayabilir - ya mantıklı bir hata yaptınız ve Goodman'ı kontrol etmeyi unuttum ya da belki Goodman kontrol ettiğinizde ve ona baktığınız zaman evlendi. (Moriarty kodunuzun her parçasını izliyor ve sizi yukarı çıkarmaya çalışıyorsa, bu mantığı değerlendirmenize yardımcı olur.)

Goodman'ın araması orada olmadığı zaman ne yapar? Bir sıfır olmadan, bir tür varsayılan müşteriye geri dönmeniz gerekir - ve şimdi bu varsayılana bir şeyler satıyorsunuz.

Temel olarak, ne ya da doğru çalışması ne olursa olsun, kodun çalışmasının daha önemli olup olmadığı ortaya çıkar. Eğer uygunsuz davranış hiçbir davranışa tercih edilmiyorsa, boş değer istemezsiniz. (Bunun nasıl doğru seçim olabileceğini gösteren bir örnek için, Ariane V'in ilk lansmanını düşünün. Yakalanmamış / 0 hatası, roketin sert bir dönüş yapmasına ve bunun sonucunda parçalandığında kendi kendini imha etmesine neden oldu. aslında, yükseltici yakıldığı anda artık hiçbir amaca hizmet etmiyordu - rutin geri dönüş çöplerine rağmen yörüngeye dönecekti.)

100 üzerinden en az 99 kez null kullanmayı tercih ederdim. Yine de, sevinç için kendi versiyonlarına dikkat ederek atlardım.


1
Bu iyi bir cevap. Programlamadaki boş yapı sorun değil, hepsi boş değerlerin örnekleri. Varsayılan bir nesne yaparsanız, sonunda tüm boş değerleriniz bu varsayılanlarla değiştirilecektir ve UI, DB ve bunların arasındaki her yer bunun yerine muhtemelen daha kullanışlı olmayanlarla doldurulacaktır. Ama geceleri uyuyacaksın çünkü en azından programın çöküyor sanırım.
Chris McCall

2
Bunun nullbir değerin yokluğunu modellemenin tek (ya da hatta tercih edilen) bir yolu olduğunu varsayıyorsunuz .
sara

1

En yaygın durum için optimize edin.

Her zaman null değerinin kontrol edilmesi sıkıcıdır - yalnızca Müşteri nesnesini ele geçirip onunla çalışabilmek istersiniz.

Normal durumda, bu sadece iyi çalışması gerekir - sen yukarı bak, nesneyi al ve kullan.

Gelen istisnai durumda size (rastgele) adında bir müşteriyi arıyorsanız, o rekor / nesne var olup olmadığını bilmeden, bu başarısız olduğuna dair bazı göstergeler gerekiyordu. Bu durumda, cevap RecordNotFound istisnasını atmaktır (veya altındaki SQL sağlayıcısının bunu sizin için yapmasına izin veriniz).

Belki bir kullanıcı tarafından girildiği için gelen verilere (parametre) güvenip güvenemeyeceğinizi bilemeyeceğiniz bir durumdaysanız, 'TryGetCustomer (name, out out customer)' seçeneğini de Desen. İnt.Parse ve int.TryParse ile çapraz referans.


Bir işleve girdiğinden ve bir tür null olduğu için gelen verilere güvenip güvenemeyeceğinizi asla bilemeyeceğinizi iddia ediyorum. Girdiyi tamamen farklı kılmak için kod yenilenebilir. Eğer boş bir olasılık varsa kontrol etmelisin. Böylece, her değişkenin erişilmeden önce her seferinde boş bırakıldığı kontrol edilen bir sisteme sahip olursunuz. Kontrol edilmediği durumlar, programınızın başarısızlık yüzdesi haline gelir.
Chris McCall

0

İstisnalar değerlendirme değil!

Onlar bir sebep için orada. Eğer kodunuz kötü çalışıyorsa, istisna denilen bir dahi modeli vardır ve size bir şeylerin yanlış olduğunu söyler.

Boş nesneleri kullanmaktan kaçınarak, bu istisnaların bir kısmını saklıyorsunuzdur. Boş gösterici istisnasını iyi yazılmış bir istisnaya dönüştürdüğü OP örneğinden bahsetmiyorum, bu aslında okunabilirliği arttırdığı için iyi bir şey olabilir. Nasıl hiç alırken Opsiyon tipi @Jonas belirttiği gibi çözüm sen istisnalar saklıyorsun.

Üretim uygulamanızda, boş bir seçenek seçmek için düğmeye tıklandığında atılacak istisna yerine, sadece hiçbir şey olmuyor. Boş gösterici istisnası yerine atılır ve muhtemelen bu istisna hakkında bir rapor alırız (birçok üretim uygulamasında olduğu gibi, böyle bir mekanizmaya sahibiz) ve gerçekte düzeltebileceğimizden.

Kodunuzu istisnalardan kaçınarak kurşun geçirmez hale getirmek kötü bir fikirdir; istisna düzelterek, kurşun geçirmez kodunu seçmenizi sağlar.


1
Şimdi Seçenek türü hakkında birkaç yıl önce soruyu gönderdiğimden daha fazla şey biliyorum, çünkü bunları düzenli olarak Scala'da kullanıyorum. Seçenek'in amacı, Nonebir Seçenek olmayan bir şeye derleme zamanı hatasının atanmasını ve benzer şekilde Optionilk önce derleme zamanı hatası olup olmadığını kontrol etmeden bir değeri varmış gibi kullanmasıdır . Derleme hataları kesinlikle çalışma zamanı istisnalarından daha iyi.
Tim Goodman

Örneğin: Söyleyemezsiniz s: String = None, söylemelisiniz s: Option[String] = None. Ve eğer sbir Seçenek ise , söyleyemezsiniz s.length, ancak bir değere sahip olup olmadığını kontrol edebilir ve aynı zamanda deseni eşleştirerek değeri çıkarabilirsiniz:s match { case Some(str) => str.length; case None => throw RuntimeException("Where's my value?") }
Tim Goodman

Maalesef Scala'da yine de söyleyebilirsiniz s: String = null, ancak bu Java ile birlikte çalışmanın bedeli. Genellikle Scala kodumuzda bu tür şeylere izin verilmez.
Tim Goodman,

2
Ancak, istisnaların (doğru kullanıldığında) kötü bir şey olmadığı ve bir istisnayı yutmakla "düzeltmek" genel bir fikir olduğunu kabul ediyorum. Ancak, Seçenek türüyle amaç, istisnaları daha iyi bir şey olan derleme zamanı hatalarına dönüştürmektir.
Tim Goodman

@TimGoodman sadece scala taktik midir, yoksa Java ve ActionScript 3 gibi diğer dillerde de kullanılabilir mi? Ayrıca cevabınızı tam bir örnekle düzenleyebilmeniz iyi olurdu.
Ilya Gazman

0

NullsSorunlu oldukları için açıkça kontrol edilmeleri gerekir, ancak derleyici onları kontrol etmeyi unuttuğunuzu söyleyemez. Bunu yalnızca zaman alan statik analiz size söyleyebilir. Neyse ki, birkaç iyi alternatif var.

Değişkeni kapsam dışına çıkarın. Çok sık, nullbir programcı bir değişkeni çok erken ilan ettiğinde ya da çok uzun süre beklettiğinde yer tutucu olarak kullanılır. En iyi yaklaşım sadece değişkenden kurtulmaktır. Oraya koymak için geçerli bir değeriniz olana kadar beyan etmeyin. Bu, düşündüğünüz kadar zor bir kısıtlama değildir ve kodunuzu çok daha temiz hale getirir.

Boş nesne desenini kullanın. Bazen, eksik bir değer sisteminiz için geçerli bir durumdur. Boş nesne deseni burada iyi bir çözümdür. Sürekli açık kontrollere olan ihtiyacı önler, ancak yine de boş bir durumu temsil etmenize izin verir. Bazılarının iddia ettiği gibi, bu bir "hata koşulu üzerinde kâğıt" değildir, çünkü bu durumda boş bir durum geçerli bir anlamsal durumdur. Olduğu söyleniyor, boş bir durum geçerli bir anlamsal durum değilse, bu modeli kullanmamalısınız . Değişkenini kapsam dışına çıkarmalısın.

Bir Belki / Seçenek kullanın. Her şeyden önce, bu derleyicinin sizi eksik bir değeri kontrol etmeniz gerektiği konusunda uyarmasına izin verir, ancak bir tür açık kontrolü başka bir şeyle değiştirmekten fazlasını yapar. Kullanarak Options, kodunuzu zincirleyebilir ve değeriniz varmış gibi devam ettirebilirsiniz, en son dakikayı tam olarak kontrol etmenize gerek kalmaz. Scala'da örnek kodunuz şuna benzer:

val customer = customerDb getByLastName "Goodman"
val awesomeMessage =
  customer map (c => s"${c.firstName} ${c.lastName} is awesome!")
val notFoundMessage = "There was no customer named Goodman.  How lame!"
println(awesomeMessage getOrElse notFoundMessage)

İkinci satırda, müthiş mesajı oluşturduğumuz yerde, müşterinin bulunup bulunmadığını ve ihtiyacımız olmadığını güzel bir şekilde kontrol etmiyoruz . Birçok satır sonra, hatta biz açıkça ne olur ilgilenmemiz farklı bir modül, içinde olabilir çok son satır kadar değil Optionise None. Sadece bu değil, yapmayı unutmuş olsaydık, kontrol edilmiş türü olmazdı. O zaman bile, açıkça ififade etmeden, çok doğal bir şekilde yapılır .

Cihazın nulltest ettiği bir kullanım durumu sırasında şanslıysanız, yazının sadece iyi olduğu, ancak yolun her adımında açık bir kontrol yapmanız gereken veya tüm uygulamanızın havaya uçtuğu bir kontrast ile karşılaştırılması . Sadece uğraşmaya değmez.


0

NULL'ın temel sorunu, sistemi güvenilmez hale getirmesidir. 1980'de Turing Ödülüne adanmış gazetede Tony Hoare şunları yazdı:

Ve böylece, ADA'nın yaratıcıları ve tasarımcılarına tavsiyem en iyisi görmezden gelindi. .... Bu dilin bugünkü haliyle güvenilirliğin kritik olduğu uygulamalarda kullanılmasına izin vermeyin, örneğin nükleer santraller, seyir füzeleri, erken uyarı sistemleri, antibalistik füze savunma sistemleri. Bir programlama dili hatası nedeniyle yoldan çıkacak bir sonraki roket, Venüs'e zararsız bir yolculukta keşfedilen bir uzay roketi olmayabilir: Kendi şehirlerimizden birinin üzerinde patlayan nükleer bir savaş başlığı olabilir. Güvenilmez programlar üreten bir güvenilmez programlama dili, çevremiz ve toplumumuz için güvensiz otomobillerden, zehirli böcek ilacı veya nükleer santrallerdeki kazalardan çok daha büyük bir risk oluşturmaktadır. Riski azaltmak için değil, riski azaltmak için dikkatli olun.

ADA dili bundan beri çok değişti, ancak bu tür sorunlar Java, C # ve diğer birçok popüler dilde hala mevcut.

Bir müşteri ile tedarikçi arasında sözleşmeler yapmak geliştiricinin görevidir. Örneğin, C # 'da, Java'da olduğu gibi, salt okunur (iki Seçenek) oluşturarak referansın Genericsetkisini en aza indirmek için kullanabilirsiniz :NullNullableClass<T>

class NullableClass<T>
{
     public HasValue {get;}
     public T Value {get;}
}

ve sonra kullanın

NullableClass<Customer> customer = dbRepository.GetCustomer('Mr. Smith');
if(customer.HasValue){
  // one logic with customer.Value
}else{
  // another logic
} 

veya C # extension yöntemleriyle iki seçenek stili kullanın:

customer.Do(
      // code with normal behaviour
      ,
      // what to do in case of null
) 

Fark önemli. Bir yöntemin müşterisi olarak ne bekleyeceğinizi biliyorsunuz. Bir takım kurala sahip olabilir:

Bir sınıf NullableClass türünde değilse, örneği boş olmamalıdır .

Ekip, bu fikri Sözleşme ile Tasarım ve derleme zamanında statik kontrol kullanarak , örneğin ön koşulla:

function SaveCustomer([NotNullAttribute]Customer customer){
     // there is no need to check whether customer is null 
     // it is a client problem, not this supplier
}

veya bir dize için

function GetCustomer([NotNullAndNotEmptyAttribute]String customerName){
     // there is no need to check whether customerName is null or empty 
     // it is a client problem, not this supplier
}

Bu yaklaşım, uygulama güvenilirliğini ve yazılım kalitesini büyük ölçüde artırabilir . Sözleşme ile Tasarım bir durumdur Hoare mantığı 1988 yılında ünlü Nesne Tabanlı Yazılım İnşaat kitap ve Eyfel dilinde Bertrand Meyer tarafından doldurulan, ama modern bir yazılım işçiliği Geçersiz Şekilde kullanımda değil.


0

Hayır.

Bir dilin özel bir değeri hesaba katmaması null, dilin problemidir. Yazarı, her karşılaşmada boş bir değer olasılığı ile açıkça başa çıkmaya zorlayan Kotlin veya Swift gibi dillere bakarsanız , o zaman tehlike yoktur.

Söz konusu dil gibi dillerde, dil nullherhangi bir türden bir değer olmasına izin verir , ancak daha sonra bunu kabul etmek için herhangi bir yapı sağlamaz, bu da nullbeklenmedik bir şekilde (özellikle başka bir yerden size iletildiğinde) olaylara yol açar. Böylece çarpışırsınız. Bu kötülük: nullbaşa çıkmadan kullanmanıza izin vermek .


-1

Temel olarak ana fikir, boş gösterici referans sorunlarının çalışma zamanı yerine derleme zamanında yakalanması gerektiğidir. Bu nedenle, bazı nesneler alan bir işlev yazıyorsanız ve kimsenin null başvurusu ile çağırmasını istemiyorsanız, system yazın, bu derleyicinin işlevinize yapılan çağrının hiçbir zaman olmayacağının garantisini vermek için kullanabilmesi için bu gereksinimi belirtmenize izin vermelidir Arayan kişi ihtiyacınızı karşılamıyorsa derleyin. Bu, örneğin türlerinizi dekore etmek veya seçenek türleri (bazı dillerde null olarak da adlandırılabilir) olarak kullanmak gibi birçok yolla yapılabilir, ancak açıkçası derleyici tasarımcıları için çok daha fazla iş vardır.

1960'larda ve 70'lerde, derleyici tasarımcısının bu fikri hayata geçirmediği için anlaşılabilir olduğunu düşünüyorum çünkü makineler kaynaklar açısından sınırlıydı, derleyiciler nispeten basit tutulmalıydı ve hiç kimse bunun ne kadar kötü olacağını bilmiyordu. yıl aşağı çizgi.


-1

Buna karşı basit bir itirazım var null:

Belirsizlik getirerek kodunuzun anlamını tamamen bozar .

Çoğu zaman sonucun belirli bir türde olmasını beklersiniz . Bu anlamsal olarak ses. Diyelim, veritabanından belirli bir kullanıcı için belirli bir soru sordunuz, idözgeçmişin belirli bir türde (= user) olmasını beklersiniz . Ancak, bu kimliğin kullanıcısı yoksa? Bir (kötü) çözüm: bir nulldeğer eklemek . Böylece sonuç belirsizdir : ya öyle userya da öyle null. Ancak nullbeklenen tip değil. İşte kod kokusunun başladığı yer burasıdır .

Kaçınmada null, kodunuzu semantik olarak netleştiriyorsunuz.

Her zaman etrafta yol vardır null: koleksiyonlara yeniden bakmak Null-objects, optionalsvb.


-2

Bunun için bir değer hesaplamak üzere kod çalıştırılmadan önce erişilen referans veya işaretçi tipindeki bir depolama konumunun semantik olarak mümkün olması durumunda, ne olması gerektiği konusunda mükemmel bir seçenek yoktur. Bu konumların varsayılan olarak serbestçe okunabilen ve kopyalanabilen, ancak referanslara alınmadıklarında veya indekslendiklerinde hatalı olacak olan işaretçi referanslarını varsayılan olarak alması olası bir seçimdir. Diğer seçenekler şunlardır:

  1. Konumları varsayılan olarak bir boş göstericiye getirin, ancak kodun kendilerine bakmasına izin vermeyin (hatta null olduklarını bile belirlemez) Muhtemelen boş bir işaretçi ayarlamak için açık bir yol sağlar.
  2. Konumları varsayılan olarak bir boş göstericiye getirin ve bir tane okuma girişiminde bulunulursa kilitlenir, ancak bir göstericinin boş tutup tutmadığını test etmek için kilitlenmeyen bir yöntem sunar. Ayrıca, bir işaretçiyi null değerine ayarlamak için açık bir yol sağlar.
  3. Belirtilen türün derleyici tarafından sağlanan belirli bir varsayılan örneğine işaretçiyi varsayılan olarak konumlandırın.
  4. Belirtilen türün program tarafından sağlanan belirli bir varsayılan örneğine işaretçiyi varsayılan olarak konumlara getirin.
  5. Herhangi bir boş gösterici erişimine sahip olmanız (sadece referans işlemleri değil) bir örnek sağlamak için program tarafından sağlanan rutini çağırır.
  6. Dil semantiğini, geçici olarak erişilemeyen bir derleyici dışında, başlangıç ​​rutinleri tüm üyelerde çalıştırılana kadar (bir dizi kurucuya benzer bir örnek, varsayılan bir örnekle tedarik edilmek zorunda kalacaktı), depolama yerlerinin koleksiyonları olmayacak şekilde tasarlayın. bir örneği döndürecek bir işlev veya muhtemelen bir işlev çifti - biri örneği döndürmek için diğeri, dizinin yapımı sırasında bir istisna meydana gelirse önceden oluşturulmuş durumlarda çağrılacak olan).

Son tercihin, özellikle hem null hem de null olmayan türler içeren bir dil varsa (biri herhangi bir tür için özel dizi yapıcılarını çağırabilir, ancak null olmayan türlerin dizilerini oluştururken onları çağırmak için gerekli olabilir) bazı çekiciliğe sahip olabilir. ancak boş göstericileri icat ettiği zaman muhtemelen mümkün olmazdı. Diğer seçeneklerden hiçbiri, boş göstericilerin kopyalanmasına izin vermekten, itiraz edilmemesine veya dizine eklenmesine izin vermek kadar çekici görünmemektedir. Yaklaşım # 4 bir seçenek olarak uygun olabilir ve uygulanması oldukça ucuz olmalıdır, ancak kesinlikle tek seçenek olmamalıdır. İşaretçilerin varsayılan olarak belirli bir geçerli nesneye işaret etmeleri gerekmesi, işaretçilerin varsayılan olarak okunamayan veya kopyalanabilen ancak değiştirilemeyen veya dizine eklenmemiş bir boş değere sahip olmasından çok daha kötüdür.


-2

Evet, NULL, nesne yönelimli dünyada korkunç bir tasarım . Özet olarak, NULL kullanımı şunlara yol açar:

  • geçici hata işleme (istisnalar yerine)
  • belirsiz anlamsal
  • hızlı başarısızlık yerine yavaş
  • bilgisayarla düşünme vs nesne düşünme
  • değiştirilebilir ve eksik nesneler

Ayrıntılı bir açıklama için bu blog gönderisine bakın: http://www.yegor256.com/2014/05/13/why-null-is-bad.html

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.