assert mutlaka düzeltilmeli
(kristoff.it)- assert, önkoşulları, sonkoşulları ve değişmezleri kodda açıkça belirtme aracıdır; tür sistemiyle zorunlu kılınabilen kısıtların dil özellikleriyle ifade edilmesi tercih edilir
- Zig’de
std.debug.assert, makro değil normal bir fonksiyondur;unreachableile ulaşılamaz yolları işaretler ve optimizasyonda da kullanılır - Debug ve ReleaseSafe’te başarısız assert bir panic ile çöküşe yol açarken, ReleaseFast ve ReleaseSmall’da unchecked illegal behavior nedeniyle yanlış çalışmaya neden olabilir
- Prodüksiyonda assert’i kapatmak, yanlış varsayımları erken fark etme fırsatını ortadan kaldırır ve sonrasında kodun hatalı assert’lere dayanarak güvenlik açıklarına dönüşmesine yol açabilir
- ReleaseSafe ile ReleaseFast arasında seçim yapmak programın önceliklerine bağlıdır; ancak asıl nokta assert’i örtbas edip kapatmak değil, hatalı assert’leri düzeltmektir
assert’in rolü ve Zig’in varsayılan davranışı
- assert, “bu argüman null olamaz”, “bu tamsayı tek olamaz” gibi koşulların her zaman doğru olması gerektiğini kodla ifade etme aracıdır
- Örnek:
assert(my_arg != null);,assert(my_num % 2 != 0); - Eğer tür sistemiyle kısıtlar zorunlu kılınabiliyorsa, assert yerine dil özelliklerini kullanmak daha iyidir
- Zig’de normal işaretçi
*Foonull olamaz; isteğe bağlı işaretçi?*Foonull olabilir ama değere erişmeden önce kontrol zorunludur
- Örnek:
- assert; önkoşulları, sonkoşulları ve değişmezleri belirtmek için uygundur
- İyi yazılmış assert’ler, programlama hatalarını yakalamada birim testlerinden daha güçlü olabilir
- Fuzzing ile birlikte kullanıldığında assert’in etkisi daha da artabilir
Zig’de unreachable ve assert
- Zig’de assert, hatalı kod yolunu işaretleyen bir dil özelliği olan
unreachableüzerine kuruludurswitchiçinde ulaşılamaz bir dal.a => unreachableşeklinde işaretlenebilirunreachablehem bir ifade (statement) olarak hem de herhangi bir türden ifade gereken yerlerde kullanılabilir- Ulaşılamaz bir durumda zorla geçici bir değer üretmek gerekmez
- Zig standart kütüphanesindeki
std.debug.assertşu şekilde uygulanırpub fn assert(ok: bool) void { if (!ok) unreachable; // assertion failure } unreachablebilgisi optimizasyon için kullanılabilir- Derleyici ulaşılamaz yolları kaldırabilir, bu bilgi yayılabilir ve yerel olmayan optimizasyonlar mümkün hale gelir
- Her assert performans artışı sağlamaz ama programcının kolayca öngöremeyeceği optimizasyonlar da mümkün olabilir
Derleme modları ve çalışma zamanı güvenliği
- Zig’de Debug, ReleaseSafe, ReleaseFast ve ReleaseSmall derleme modları vardır
- Bu ayarların programın tamamına yalnızca global olarak uygulanması gerekmez
- Her bağımlılık farklı modlarla derlenebilir ve
@setRuntimeSafetykullanılırsa çalışma zamanı güvenliği fonksiyon içindeki blok düzeyinde de ayarlanabilir
- assert başarısızlığı Zig’de “illegal behavior” sayılır
- Checked modlar olan Debug, ReleaseSafe ve
@setRuntimeSafety(true)altında panic ile program çöker - Unchecked modlar olan ReleaseFast, ReleaseSmall ve
@setRuntimeSafety(false)altında “unchecked illegal behavior” oluşur ve program yanlış çalışır
- Checked modlar olan Debug, ReleaseSafe ve
- unchecked illegal behavior sonucunda ne olacağı garanti edilmez
- Örnek
switchte, şu an üretilen makine kodunun özellikleri nedeniyle başka bir dala atlıyormuş gibi görünebilir - Farklı bir derleyici sürümünde bambaşka bir yanlış davranış ortaya çıkabilir
- İlgili davranış godbolt örneğinde görülebilir
- Örnek
- assert ve sonrasındaki
switchin ReleaseSafe ile ReleaseFast’te nasıl farklılaştığı başka bir godbolt örneğinde görülebilir- ReleaseFast’te fonksiyonun tüm karşılaştırmaları atlayıp
truedöndürdüğü bir yapı ortaya çıkar - Bu tür optimizasyonlar, video oyunları ve diğer gerçek zamanlı medya uygulamalarının yoğun biçimde dayandığı davranışlardır
- ReleaseFast’te fonksiyonun tüm karşılaştırmaları atlayıp
Zig assert bir makro değildir
- Zig’de
std.debug.assert, makro değil normal bir fonksiyondur- Zig’de makro yoktur
- Bu özellikle C/C++ geliştiricilerinin Zig’e yaklaşırken şaşırdığı bir noktadır
- C/C++’ta assert devre dışı bırakıldığında, assert çağrısının tamamı ve ona verilen ifade yorum satırı haline gelmiş gibi davranması yaygındır
- Bu yüzden C/C++’ta yan etkili ifadeler assert içine konmamalıdır
- Çünkü assert kapatıldığında o işlemin kendisi de ortadan kalkabilir
- Zig’de fonksiyon çağrısı kurallarına göre argümanlar fonksiyon çağrısından önce değerlendirilir
std.debug.assertiç mantığından bağımsız olarak argüman ifadesi değerlendirilir- Bu nedenle aşağıdaki gibi yan etkili ifadeler de assert içine konabilir
// assert that the remove operation is not a noop: assert(my_map.remove("expected-to-exist")); - Buna karşılık assert koşulunu hesaplamak için karmaşık işlemler gerekiyorsa, unchecked modda bile bu hesaplamanın mutlaka kaldırılacağı garanti değildir
- Böyle durumlarda kod
comptime ifile korunmalıdır
const builtin = @import("builtin"); if (builtin.mode == .Debug) { var condition = ...; // whatever bookkeeping is necessary // to compute the condition assert(condition == .ok); } - Böyle durumlarda kod
- C/C++ anlam bilimlerine alışkın olanlara yabancı gelebilir ama Zig’de genel varsayım assert’in normalde kapatılmadığıdır
Prodüksiyonda assert kapatmanın sorunu
- assert için kabaca üç seçenek vardır
- Onu çalışma zamanı kontrolü olarak tutup başarısız olduğunda sürecin panic ile çökmesine izin vermek
- assert’i performans optimizasyonu için kullanıp assert yanlışsa programın yanlış çalışmasını göze almak
- assert’i tamamen devre dışı bırakmak
std.debug.assert, assert’i tamamen devre dışı bırakmayı varsayılan olarak desteklemez- Derleme anındaki bayrağı içeride kontrol eden özel bir assert uygulanırsa C/C++ tarzına daha yakın bir davranış üretilebilir
- assert’i kapatma isteği genelde iki nedenin birleşiminden doğar
- Performans maliyetini veya uygulamanın çökmesini istememek nedeniyle çalışma zamanı kontrolünü sürdürmek istenmez
- assert’in her zaman doğru olduğuna güvenmek zor olduğu için, optimizasyonda kullanıldığında ortaya çıkabilecek yanlış çalışmadan korkulur
- matklad’ın ilgili tartışmada hatırlattığı gibi, çöküşten kaçınmak için meşru mühendislik gerekçelerinin bulunduğu durumlar vardır
- Ancak genel yazılım dünyasında çöküşten kaçınmayı varsayılan yapmak kötü bir tercih olarak değerlendirilir
- assert devre dışı bırakılırsa, imkânsız kabul edilen bir koşul gerçekten oluştuğunda bile program çalışmayı sürdürür
- Program yanlış bir varsayım altında çalışmaya devam eder; bu da unchecked illegal behavior olmasa bile bir yanlış çalışma biçimidir
- unchecked illegal behavior veya C’deki undefined behavior tehlikelidir çünkü programı bir weird machine haline getiren bir yol olabilir
- Yeterince karmaşık yazılımlarda UIB olmasa bile program istenmeyen şekillerde bükülebilir
- Çalışma anında assert’in false olması, tanımın dışına çıkmak demektir ve bu tek başına istenmeyen işler yaptırabilir
- SQL injection, UIB olmadan da weird-machine düzeyinde yanlış çalışmaya yol açabilen somut ve yaygın bir örnektir
- Programın yanlış çalışma maliyeti çok yüksekse, assert’i açık bırakmak daha doğrudur
- Performans çok kritikse ve yanlış çalışma riski göze alınabiliyorsa, assert’i optimizasyon fırsatı olarak kullanmak daha uygundur
- assert’i devre dışı bırakmak, hem performans kazancını kaçırmaya hem de gerçekte olduğundan daha güvenli sanmaya yol açabilir
Hatalı assert’in kod tabanını kandırma biçimi
- Asıl risk, yanlış assert’in testlerde ortaya çıkmayıp yalnızca prodüksiyonda başarısız olabilmesidir
- Eğer tüm assert’lerin her zaman doğru olduğu garanti edilebilseydi, assert’i optimizasyon için kullanmak tartışmalı olmazdı
- Testlerin tüm yanlış assert’leri yakalayacağı garanti edilebilseydi, prodüksiyon optimizasyonu da güvenli olurdu
- Gerçekte yanlış assert yazılabilir ve testlerin bunu mutlaka yakalaması da garanti değildir
- Prodüksiyonda assert’i kapatmak, yanlış assert’i olabildiğince erken fark etme fırsatını ortadan kaldırır
- Daha ciddi sorun ise, sonrasında kodun bu yanlış assert’e dayanarak yazılmaya devam etmesidir
- Örnek kodda
processThingfonksiyonunun yalnızca zaten başlatılmış birthingüzerinde çağrılması gerektiği varsayımı assert ile belirtilirfn processThing(thing: Thing) void { // this function must always be invoked on // a thing that has already been started assert(thing.is_started); // ... } - Bu assert testlerde başarısız olmazken prodüksiyonda devre dışı olduğundan gerçekte false olabileceği gözden kaçabilir
- Kullanıcının görebildiği bir yanlış davranış yoksa, sorun yokmuş gibi görünüp geliştirme devam edebilir
- Sonrasında biri,
thingzaten başlatılmış olduğu için ek hazırlık olmadanbazçağrılabileceğini varsayarak koda ekleme yapabilirfn processThing(thing: Thing) void { // this function must always be invoked on // a thing that has already been started assert(thing.is_started); // ... // Since thing is already started, we don't // need to foo the bar before bazzing the qux. // It would be really bad to baz the qux otherwise, // so we add an assert for good measure. assert(thing.is_fooed); thing.baz(qux); } - İkinci assert kendi başına mantıksal olarak doğru olsa bile, ilk assert gerçekte false olabiliyorsa tehlike doğar
- Testlerde ilk assert başarısız olmadığı için ikinci assert de başarısız olmaz
- Prodüksiyonda assert devre dışı olduğundan, güvenlik açığının kod tabanına girdiği an fark edilmeyebilir
- Koddaki assert’ler geliştiriciyi yanıltır hale geldiyse, doğru kod yazmak mantıksız derecede zorlaşır
Seçenekler programın önceliklerine göre değişir
- Her programın öncelikleri farklıdır; bazı programlarda yanlış çalışma riskini en aza indirmektense performansa öncelik vermek meşru olabilir
- Bu durumda assert’i optimizasyon fırsatına dönüştürmek doğal bir seçimdir
- Prodüksiyonda assert’i alışkanlıkla devre dışı bırakmak; assert’i açık bırakmaktan da, performans optimizasyonlarını bilinçli şekilde kullanmaktan da daha kötü bir tercih olarak değerlendirilir
- Zine bir statik site üreticisidir ve şu anda ağırlıklı olarak kişisel blog derlemeleri için kullanılır
- Tehdit modeli tanımlı değildir ve bu en yüksek öncelik de değildir
- Hugo’dan bir mertebe daha hızlı çalışmasını tercih ettiği için ReleaseFast derlemeleri dağıtır
- Awebo pre-alpha aşamasında, kendi kendine barındırılabilen bir Discord alternatifidir
- Kişisel veriler işleyeceği ve internete açık bir yazılım olacağı şimdiden açıktır
- Dağıtım zamanı geldiğinde ReleaseSafe derlemeleri sunmayı planlamaktadır
- Ancak FFmpeg, Xiph Opus ve SQLite gibi bazı çekirdek bağımlılıkları ReleaseFast ile derlemeyi planlamaktadır
- Çünkü bu bağımlılıklarda performans artışının, programın yanlış çalışma riskini daha da azaltmaktan açıkça daha önemli olduğu düşünülmektedir
Gerçek projelerin tercihleri ve güvenlik örnekleri
- TigerBeetle bir finansal veritabanıdır ve assert’i her zaman açık tutar
- Ghostty bir terminal emülatörüdür ve macOS için ReleaseFast derlemeleri dağıtır
- Aşağı akış tüketicilere, örneğin Linux dağıtım paketleyicilerine de aynı yaklaşımı önerir
- Ghostty için yayımlanan nispeten ciddi iki CVE’nin ikisinde de bellek bozulması olmadan keyfi komut çalıştırılabiliyordu
- Risk yalnızca bellek bozulması veya UIB’den ibaret değildir
Zig’de tamamen kaybolmayan örtük assert’ler
- Özel assert’ler devre dışı bırakılabilse bile, Zig dilinin kod içine örtük biçimde eklediği assert’ler devre dışı bırakılamaz
- Tamsayı taşması, sıfıra bölme ve dizi sınırının aşılması buna dahildir
- Bu koşullar ya çalışma anında panic üretir ya da optimizasyon amacıyla kullanılır
- Prodüksiyonda assert kapatma pratiği, hatalı assert’lerin kod tabanı içinde çürüyüp çoğalmasına yol açabilir
- Bunun sonucu olarak UIB’ye karşı paranoya artabilir ve geliştiriciler assert’i yeniden açıp sonucu görmeye bilinçsizce korkar hale gelebilir
- Kaçınılmaz sonuç, assert’i kapatarak üstünü örtmek değil, hatalı assert’leri düzeltmek gerektiğidir
- Program doğruluğu bir alt küme için değil, bütün olarak hedeflenmelidir
1 yorum
Lobste.rs görüşleri
assertiçinde doğrudan çökme yaratmanın ya da Rust’taki panic gibi yalnızca işi çökertmenin genelde en iyi seçenek olduğuna katılıyorum. Amaasserti optimizasyon ipucu olarak kullanmanın, onu basitçe kaldırmaktan her zaman daha iyi olduğuna katılmak zor.Birincisi, rastgele bir
assertçoğu zaman optimizasyona pek yardımcı olmaz ve optimizasyon aracının hemen kullanamayacağı birçok koşul vardır. “Bu dala asla girilmez” gibi doğrudan bir varsayım koymak yerine kodun her tarafına rastgele varsayımlar serpiştirmenin getireceği performans kazancı muhtemelen büyük olmayacaktır.İkincisi,
asserti varsayıma dönüştürmek bir hatanın etki alanını ciddi biçimde büyütür. Örneğin proje ya da kullanıcı bazında ayrılmış verileri işleyen bir sistemde, aslında imkânsız olması gereken bir durumu yakalayanassertin bir hesaplama fonksiyonunun ortasında bulunduğunu düşünün. Release derlemesinde maliyeti yüksek olduğu için kapatıldığında, basit devre dışı bırakma durumunda etki tek bir proje ya da kullanıcıyla sınırlı kalabilir ve sonraki kontrollerde yakalanabilir. Buna karşılık bunu tanımsız davranışa çevirirseniz hesaplama alakasız bir koda sıçrayabilir, belleği rastgele bozabilir ve tüm projelerin verilerini bozabilir.Sonuç olarak release derlemesinde varsayılan olarak güvensiz
assertseçmek, bir sorun çıktığında hasarı yerelleştirme ihtimalini azaltma pahasına kodun rastgele noktalarını aceleyle optimize etmek anlamına gelir. Bana göre Rust bu konuda iyi tasarlanmış:assert!()her zaman panic üretir,debug_assert!()yalnızca debug modunda panic üretir,assert_unchecked()ise debug’da panic üretip release’te optimizasyon ipucu olur.ReleaseFastyerineReleaseSafekullanılmalı.assertleri kapatmaya karşı değilim; karşı olduğum şey, genel tavsiye gibi hepsini topluca kapatmak.Performans etkisi çok büyük olduğu için release derlemesinde tutulamayacağı sonucuna varmak tamamen makul. Üstelik hesaplama maliyeti yüksek
assertler, daha önce söylendiği gibi, performans iyileşmesine yol açma ihtimali en düşük olanlardır.Zine’da buna birkaç örnek de var:
https://github.com/kristoff-it/zine/…
https://github.com/kristoff-it/zine/…
Zig’de “varsayılan release modu” yok.
assertlerin nasıl ele alınacağını her zaman kendiniz seçmeniz gerekir ve tümüne uygulanacak seçenek ya çökme ya da optimizasyondur; ikisinden biri daha varsayılan sayılmaz.Ghostty’de şu ana kadar açıklanmış görece ciddi iki CVE’nin de bellek bozulması olmadan keyfi komut çalıştırmaya yol açmış olması bana çok tuhaf geliyor. Bunun ReleaseFast ile dağıtılmış olmasına rağmen böyle olması, dünyanın işleyişine dair anlayışıma bütünüyle ters düşüyor.
Terminal emülatörleriyle çalışmış biri olarak, bunlar tam da bekleyeceğiniz türden can sıkıcı açıklar. Geliştiricileri ya da araştırmacıları küçümsemek istemem ama böyle beklenmedik bir yerde ortaya çıkan komut enjeksiyonu, bu alanda neredeyse işin doğasında var; başka alanlarda başka enjeksiyon açıklarının peşinizden gelmesine benziyor.
Prodüksiyonda “performans yüzünden”
assertleri ve sınır kontrollerini kapatma çağrısını neredeyse 40 yıldır duyuyor olmamız komik. Bu sürede bilgisayarlar birkaç büyüklük mertebesi hızlandı ve yazılım herkesin hayatına çok daha derinden girdi; dolayısıyla çalışma zamanındaki doğruluk hiç olmadığı kadar önemli hale geldi.Daha verimli bir konuşma için, eski Microsoft’ta sıradan
assert,checkvb. dışında başka yerlerde pek görmediğim bir şey vardı: raporlama amaçlı assert. Tam olarak kontrol etmediğim bir koşul var, doğru olduğunu varsayıyorum ama yanlış olursa savunmacı biçimde ele alıyorum ve bunun sahada gerçekten yanlış olup olmadığını loglar ya da telemetriyle bilmek istiyorum. Örneğin bir kullanıcının belli bir listeye 1000’den fazla öğe koymayacağını varsayıp ikinci dereceden bir algoritma kullanmak ya da ağ gecikmesinin 200 ms’nin altında olacağını varsayıp çok sayıda gidiş-dönüş gerektiren bir protokol kullanmak gibi.checkten farkı ne?Burada bağlantısı verilen kişilerden biri olarak, bunun
asserthakkındaki görüşlerimi gülünç bir sahte ikileme ve karikatüre dönüştürdüğünü düşünüyorum. Başka bir yorumda da yazdığım gibi, tanımsız davranışa dönüştürülüp dönüştürülmeyeceğineassertbazında karar verilmesini tercih ediyorum.ReleaseFaste yönelik eleştirim, bu seçimi belirli bir kapsam içindeki tümassertlerle ve hatta tüm güvenlik kontrolleriyle paket halinde bağlaması.Düzeltilmemiş
assertin çökme yaratıyor diye kapatılmasının aptalca olduğu yönündeki kristoff yorumuna katılıyorum. Ancak “çökme ya da tanımsız davranış”ın tek makul alternatifler olduğu fikrine katılmıyorum. Kardeş yorumdaki goldstein’ın görüşü benimkine daha yakın.assert_unchecked()davranışını küresel varsayılan yapmak savunulması zor bir şey, ama performans optimizasyon tekniği olarak makul olabilir. Tümassertler varsayıma çevrildiğinde prodüksiyon derlemesi ciddi ölçüde hızlanıyorsa, performans artışının çoğunu üreten az sayıdaki varsayım, umarız tek bir varsayım olabilir ve bunu ikili arama benzeri yöntemlerle bulabilirsiniz.ReleaseSafeileReleaseFast/ReleaseSmallseçeneklerinden birini seçiyor.Program analizi literatüründe, koddaki iddiaları ya da
assertleri iki biçime ayıran bir ikilik vardır. Biri kodun çevresindeki bağlamla ilgilidir; bir fonksiyon için çağıranın sağlaması gereken koşuldur. Diğeri ise kodun kendisiyle ilgilidir; yine bir fonksiyon için fonksiyonun sağlaması gereken koşuldur.Bu ayrım, sözleşmeler ve kademeli tipler literatüründeki standart akademik kavram olan “sorumluluk (blame)” açısından bakıldığında netleşir. Bağlama ilişkin bir iddia başarısız olursa bu bizim hatamız değildir; sorumluluk bağlama ya da çağırana aittir, ancak çağıran doğru olup iddianın kendisi hatalı da olabilir. Kodun kendisine ilişkin bir iddia başarısız olursa sorumluluk bizdedir, ancak kod doğru olup iddianın kendisi hatalı da olabilir.
Fonksiyon düzeyinde önkoşul, bağlama ilişkin bir iddiadır; sonkoşul ise kodun kendisine ilişkin bir iddiadır. Yine de ikisi de kodun ortasında yer alabilir. Bazı doğrulama çerçeveleri kodla ilgili iddialar için
assert, bağlamla ilgili iddialar içinassumekullanır. Bu, bazı test çerçevelerinin, özellikle de rastgele test çerçevelerinin bunları yorumlama biçimiyle de bağlantılıdır.assertbaşarısız olursa test başarısız olarak işaretlenir,assumebaşarısız olursa test atlanır.Bu sanki Bun’a gönderme yapıyor gibi, o yüzden bağlantıyı biraz daha resmileştirmek istiyorum. Bun’ın geliştiricisi Jarred Sumner’ın 2024’te açtığı,
unreachableın ReleaseFast modunda panic üretmesi gerektiğini öneren bir Zig meselesi var. O başlıktaki Andrew Kelley ve Matthew Lugg yorumları bu tartışmayla ilgili.=> https://github.com/ziglang/zig/issues/19664
Bun kendi
assertfonksiyonlarını kullanıyor; bunlar release modunda panic üretir ya da kaldırılır, ama tanımsız davranış üretmez. Yine de Loris’in dipnotunu da akılda tutmak gerekir: “Zig, bir dil olarak, devre dışı bırakılamayan çok sayıdaasserti koda örtük biçimde ekler.”Bun konusunu fazla uzatmak istemiyorum; sonuçta küçük bir ekibin tek projesi. Esas nokta şu: En ufak bir endişeniz varsa ReleaseSafe kullanın. ReleaseSafe’in yavaş olduğuna dair bir ünü var, ama benim küçük Zig projelerimde ReleaseSafe ile ReleaseFast arasında ölçülebilir bir benchmark farkı göremedim. Buna rağmen hâlâ birçok başka dilden daha hızlı olması muhtemel.
Ya da bağlama uygunsa, ReleaseFast derlemesini dağıttıktan sonra tanımsız davranış yüzünden belirlenimsiz hata raporları gelmeye başlarsa ReleaseSafe’e geri dönebilirsiniz. Böylece hangi
assertin başarısız olduğunu ve sınır dışı erişim ya da taşma gibi durumları içeren, işe yarar hata raporları toplayıp kodu düzeltebilirsiniz. Hatta baştan ReleaseFast dağıtılmaması gereken bir bağlamda öyle bir karar vermiş olsanız bile bu yaklaşımı yine de öneririm :^)Bağımlılıkları ayarlayıp
@setRuntimeSafetykullanarak aynı yaklaşımı projenin sadece bazı bölümlerine de uygulayabilirsiniz. Sonuçta akıllıca davranma niyetiniz varsa ihtiyaç duyduğunuz araçların hepsi mevcut.assertçağrılarının içine yan etkili ifadeler koymanın kabul edilebilir olduğu şekilde yazmamak gerekir. Bu kötü bir pratiktir. Hata denetimi içinassertkullanmaktan da kaçınılmalıdır. Adil olmak gerekirse, yazarın bunu savunduğu pek söylenemez.Tersine,
assertkarmaşık bir hesaba bağlıysa unchecked modda bile o hesabın kesin olarak ortadan kaldırılmayabileceği, bu yüzdencomptime ifile korunması gerektiği de anlatılıyor.Umarım yazar, “makroların bıraktığı travmayı geride bırakıp sadeliği kabullenmek için iyi bir fırsat” sözündeki ironiyi gözden kaçırmamıştır. Çünkü bunun anlamı, “programın build modunu hesaba katıp her yere savunmacı
comptime ifler serpiştirme sadeliğini” kabul etmek oluyor.C# ile biraz sayısal hesap kodu yazıyorum ve release’te kapatılan çok sayıda
assertkullanıyorum. Bunlar sıkı döngülerin her iterasyonunda çalıştırmak için fazla pahalı, ama birim testlerinde rutinin ilk kez NaN girişi gördüğü anda hemen patlaması faydalı oluyor.Bu tür NaN’ler çoğu zaman kullanıcı girdisinden değil, örneğin optimize edicinin gitmemesi gereken bir yere gitmesi gibi kod hatalarından kaynaklanıyor ve daha iyi sınır kısıtları gerektiriyor. Elbette kullanıcı girdisinin temizlenmesi gerekebilir, ama bu algoritmanın derinlerinde değil, en dış sınırda yapılmalıdır. Kullanıcı girdisi temizlemesinin sonucunda algoritma içi değişmezleri
assertolmadan kanıtlayabilen bir ispat sistemi güzel olurdu, ama bu bir yan proje ve bozulursa kimse ölmeyecek.asserthakkındaki fikir ayrılıklarının %90’ı, bu kelimenin tanımının zayıf ve çok anlamlı olmasından kaynaklanıyor; bu da düşünmeyi ve iletişimi bulanıklaştırıyor. Bu yüzden kavramı şu üç ad altında ayırıp katı biçimde kullanmak gerekir.assert(bool)ya da Rust’taysaassert_unchecked(), programcının bunun her zaman doğru olduğuna inandığı ve derleyicinin de bunu her zaman doğru varsayarak optimizasyonda kullandığı şeydir. Eski dillerdeki denetim yapan assert çağrışımından kaçınmak için bunaassume()demek daha iyi olabilir.check(bool), koşul yanlışsa panic üretir, doğruysa devam eder; her zaman böyle davranır.debug_check(bool), debug modundacheck()ile aynıdır; release modunda ise her zaman devam eder. Pratikte bu, debug modunda varsayılan olarak açık olan--debug_checksbayrağıyla kontrol edilir.Buna ek olarak,
assert()icheck()e dönüştüren bir--check_assertsderleyici bayrağına da ihtiyaç var. Bu, kendiassertlerinden şüphe duyup doğrulamak istediğinizde kullanılır ve debug modunda varsayılan olarak açıktır. “Assert” derken neyi kastettiğiniz son derece açık değilse olgun bir tartışma yapmak mümkün değildir; sadece laf israfı olur.