Alıntı (zafer):
> invariant'ın ne işe yaradığı konusunda kafam karıştı
Nesnenin tutarlılığını denetler. Örneğin her defasında hesaplamayalım diye dikdörtgenin alanını hazırda bulunduruyoruzdur. Bir kenarının uzunluğu değiştiğinde bu hazırdaki alanı da değiştirmemiz gerekir.
Bu tabii basit bir örnek. Genel olarak nesnenin tutarlı veya kullanılabilir olabilmesi bazı şartlara bağlıdır. invariant blokları onları denetler:
invariant() {
assert(alan == genişlik * uzunluk);
}
Peki ne kazandık? Çünkü o hesap için de süre harcıyoruz: Hız kazancı için hazırda bulundurduğumuz 'alan' üyesini ilgili olsun olmasın her işlemden sonra invariant bloğu içinde tekrar tekrar genişlik*uzunluk hesabı ile karşılaştırıyoruz.
İşte -release durumunda koddan çıkartılmalarının nedenlerinden birisi budur. Kod denenmiş ve doğru çalıştığına güvenilmişse artık o denetimlere gerek yoktur.
Alıntı:
> çünkü zaten üretimi tamamlanan programları bizler her zaman -release modu
nda derlemez miyiz?
Evet ve bazen hayır. :)
Evet, teoride öyle ama eğer programın bütün kullanıcı testleri -release olmayan modda uygulanmışsa, testler geçti diye bir de -release modunda derleyiverip son kullanıcıya öyle verebilir miyiz? Ne yazık ki hayır.
Bazı programların hataları ancak -release modunda ortaya çıkar. Bunların nedenleri arasında derleyicinin kendi eniyileştirme hataları olabileceği gibi programcının tanımsız davranışlarının etkileri de olabilir.
Yani evet, programlar -release modunda kullanıma sunulurlar ama ben öyle olmayan firmalarda da çalıştım. Programlar debug modunda ne kadar denenmiş olursa olsun release modunda patlıyordu. Firmalar da gayet güzel debug modunda derlenmiş programı çıkartıyorlardı. Yapacak bir şey yok. :)
Alıntı:
> Bu olanaklar sadece programcı için hazırlarmış anlamına mı geliyor?
Evet. Zaten C ve C++'ta da assert() bir makrodur ve NDEBUG makrosu tanımlandığında bütün assert()'ler boş hale gelirler.
Ama D bu konuda ek bir yardım getiriyor: Bazen "buraya hiçbir zaman gelinmemelidir" anlamında yazılan assert(false) (ve tabii assert(0), vs.) çağrıları ise koddan çıkartılmazlar. Yani mantıksal ifadesi false veya 0 hazır değerini içeriyorsa o assert()'ler özeldirler ve -release modunda bile kodda dururlar.
assert() ve enforce() arasındaki yakınlık sözleşmeli programlamanın 'in' blokları konusunda bir güçlük getirir: Parametrelerle ilgili denetimleri 'in' bloklarına assert() olarak mı yazalım yoksa işlevin hemen başına mı yazalım?
Yani şu mu?
int kareKök(int sayı)
in {
assert(sayı >= 0, "Sayı sıfırdan küçük olamaz");
}
body
{
// ...
}
Yoksa şu mu?
int kareKök(int sayı)
{
if (sayı < 0) {
throw new Exception("Sayı sıfırdan küçük olamaz");
}
// ...
}
Ve tabii aslında enforce() ikincinin yazımını kolaylaştırıyor:
import std.exception;
int kareKök(int sayı)
{
enforce (sayı >= 0, "Sayı sıfırdan küçük olamaz");
// ...
}
Yanıt şöyle: Eğer kareKök() yalnızca programın kendi kodları tarafından çağrılıyorsa yani bu modülün kullanıcılarına açık değilse, o zaman denetim 'in' bloğuna yazılmalı. Böylece program bir kere denendikten sonra -release modunda denetimler de ortadan kalkarlar ve gereksizce genişlik*uzunluk gibi hesaplarla zaman harcamazlar.
Ama eğer bu modülün arayüzünde bulunan bir işlevse, o zaman programı biz ne kadar denemiş olursak olalım kullanıcıların yanlış parametre göndermeyeceklerinden emin olamayız. O yüzden arayüz işlevlerinin giriş koşullarını her zaman için işlevin içinde denetlememiz gerekir.
Ve bu denetimler assert() de olamazlar çünkü yanlış sonuçlar üretmek de istemediğimiz için denetimlerin ortadan kalkmalarını da istemiyoruz.
Diğer notlar:
-
Nitelik işlevleri sanki türlerin bir üyesine erişiyormuş gibi düşünülürler. Sanki nesnenin 'uzunluk', 'renk', 'ağırlık', vs. gibi bir niteliğine eriştirirler. O yüzden bu işlevlerin isimleri 'isim halinde' seçilir. Ve o yüzden bence VerFirinSicakligi yerine kısaca 'sicaklik' olmalı.
-
Benzer şekilde, IsBitisSuresi'nin de isminde eylem görülmediği için sanki bir nitelikmiş gibi algılanabiliyor. Aslında "10 saniye bekle" gibi bir açıklamaya gerek duyulmuş olması da o konuda bir gariplik olduğunu gösteriyor.
-
Şu anda Eş Zamanlı Programlama bölümünü İngilizceleştiriyorum ve doğal olarak kodları da gözden geçiriyorum ve yeniliyorum. Oradaki örneklerde ben de 'saniye' gibi süreleri int olarak tanımlamışım. O kodları int yerine Duration kullanacak şekilde değiştiriyorum.
Bu, bu koddaki IsBitisSuresi()'nin parametresinin de int olmasından aklıma geldi. Parametrenin ismini 'saniye' seçerek sürenin biriminin saniye olduğunu belirtiyoruz ama bu bile kırılgan oluyor çünkü ilerideki bir zamanda birim milisaniye'ye dönüşse parametrenin ismi saniye olarak unutulmuş olabilir.
İşte bu nedenlerle süre olarak Duration çok uygun. Çağıranlar isterlerse saniye gönderirler isterlerse başka bir birim:
import std.stdio;
import core.thread;
void bekle(Duration süre)
{
writeln("Beklemeye başladım");
Thread.sleep(süre);
writeln("Bekledim");
}
void main()
{
Duration birSüre = dur!"msecs"(500);
bekle(birSüre);
bekle(dur!"seconds"(1));
}
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]