assert İfadesi ve enforce
- Bu programı
06:09ve1:2vererek çalıştırdığınızda hata atmadığını göreceksiniz. Buna rağmen, sonucun doğru olmadığını da farkedebilirsiniz:09:06'da başlayan ve 1 saat 2 dakika süren işlem 10:08'de sonlanır.
Görüldüğü gibi,
06:09girildiği halde, çıkışa09:06yazdırılmaktadır. Bu hata, bir sonraki problemde birassertdenetimi yardımıyla yakalanacak. - Programa
06:09ve15:2verildiğinde atılan hata, bizi şu satıra götürür:string zamanDizgisi(int saat, int dakika) { assert((saat >= 0) && (saat <= 23)); // ... }
Saat bilgisinin 0 ile 23 arasında bir değerde olmasını denetleyen bu
assertdenetiminin başarısız olması, ancak bu işlev programın başka yerinden yanlışsaatdeğeriyle çağrıldığında mümkündür.zamanDizgisiişlevinin çağrıldığısonucuYazdırişlevine baktığımızda bir yanlışlık göremiyoruz:void sonucuYazdır( int başlangıçSaati, int başlangıçDakikası, int işlemSaati, int işlemDakikası, int bitişSaati, int bitişDakikası) { writef("%s'%s başlayan", zamanDizgisi(başlangıçSaati, başlangıçDakikası), daEki(başlangıçDakikası)); writef(" ve %s saat %s dakika süren işlem", işlemSaati, işlemDakikası); writef(" %s'%s sonlanır.", zamanDizgisi(bitişSaati, bitişDakikası), daEki(bitişDakikası)); writeln(); }
Bu durumda
sonucuYazdırişlevini çağıran noktalardan şüphelenir ve onun programdamainiçinden ve tek bir noktadan çağrıldığını görürüz:void main() { // ... sonucuYazdır(başlangıçSaati, başlangıçDakikası, işlemSaati, işlemDakikası, bitişSaati, bitişDakikası); }
Çağıran noktada da bir sorun yok gibi görünüyor. Biraz daha dikkat ve zaman harcayarak sonunda başlangıç zamanının ters sırada okunduğunu farkederiz:
zamanOku("Başlangıç zamanı", başlangıçDakikası, başlangıçSaati);
Programcının yaptığı o dikkatsizlik nedeniyle
06:09olarak girilen bilgi aslında09:06olarak algılanmakta ve daha sonra buna15:2süresi eklenmektedir.zamanDizgisiişlevindekiassertde saat değerini 24 olarak görür ve bu yüzden hata atılmasına neden olur.Burada çözüm, başlangıç zamanının okunduğu noktada parametreleri doğru sırada yazmaktır:
zamanOku("Başlangıç zamanı", başlangıçSaati, başlangıçDakikası);Çıktısı:
Başlangıç zamanı? (SS:DD) 06:09 İşlem süresi? (SS:DD) 15:2 06:09'da başlayan ve 15 saat 2 dakika süren işlem 21:11'de sonlanır.
- Bu seferki hata,
daEkiişlevindekiassertile ilgili:assert(ek.length != 0);O denetimin hatalı çıkması, da ekinin uzunluğunun 0 olduğunu, yani ekin boş olduğunu gösteriyor. Dikkat ederseniz,
06:09ve1:1zamanlarını toplayınca sonuç07:10olur. Yani bu sonucun dakika değerinin son hanesi 0'dır.daEkiişlevine dikkat ederseniz, 0'ın hangi eki alacağı bildirilmemiştir. Çözüm, 0'ıncasebloğunu daswitchifadesine eklemektir:case 6, 9, 0: ek = "da"; break;
Bu hatayı da bir
assertsayesinde yakalamış ve gidermiş olduk:Başlangıç zamanı? (SS:DD) 06:09 İşlem süresi? (SS:DD) 1:1 06:09'da başlayan ve 1 saat 1 dakika süren işlem 07:10'da sonlanır.
- Daha önce de karşılaştığımız
assertyine doğru çıkmıyor:assert((saat >= 0) && (saat <= 23));Bunun nedeni,
zamanEkleişlevinin saat değerini 23'ten büyük yapabilmesidir. Bu işlevin sonuna, saat değerinin her zaman için 0 ve 23 aralığında olmasını sağlayan bir kalan işlemi ekleyebiliriz:void zamanEkle( int başlangıçSaati, int başlangıçDakikası, int eklenecekSaat, int eklenecekDakika, out int sonuçSaati, out int sonuçDakikası) { sonuçSaati = başlangıçSaati + eklenecekSaat; sonuçDakikası = başlangıçDakikası + eklenecekDakika; if (sonuçDakikası > 59) { ++sonuçSaati; } sonuçSaati %= 24; }
Yukarıdaki işlevdeki diğer hatayı da görüyor musunuz?
sonuçDakikası59'dan büyük bir değer olduğundasonuçSaatibir arttırılıyor, amasonuçDakikası'nın değeri 59'dan büyük olarak kalıyor.Belki de şu daha doğru bir işlev olur:
void zamanEkle( int başlangıçSaati, int başlangıçDakikası, int eklenecekSaat, int eklenecekDakika, out int sonuçSaati, out int sonuçDakikası) { sonuçSaati = başlangıçSaati + eklenecekSaat; sonuçDakikası = başlangıçDakikası + eklenecekDakika; sonuçSaati += sonuçDakikası / 60; sonuçSaati %= 24; assert((sonuçSaati >= 0) && (sonuçSaati <= 23)); assert((sonuçDakikası >= 0) && (sonuçDakikası <= 59)); }
Aslında
sonuçDakikasıhâlâ hatalıdır çünkü ona da 60'tan kalanı atamak gerekir. Ama şimdi işin güzel tarafı, artık bu işlevin hatalı saat ve dakika değerleri üretmesiassertdenetimleri nedeniyle olanaksızdır.Yukarıdaki işlevi örneğin
06:09ve1:55değerleriyle çağırırsanız,sonuçDakikası'nı denetleyenassertdenetiminin hata vereceğini göreceksiniz. - Burada sorun, son hanenin 0 olmasından kaynaklanıyor. Son hane sıfır olunca onlar hanesini de katarak "on", "kırk", "elli", vs. diye okuyunca 0'a verilmiş olan "da" eki her durumda doğru çalışmıyor. Bu problemin çözümünü size bırakıyorum.