C ailesinden gelenler için üç sürpriz
TROIA'nın akış kontrol yapıları (IF, SWITCH, WHILE) tanıdık görünür ama üç yerde bilinçli olarak farklı davranır — ve bu farkları bilmeden yazılan kod, derlenir ama beklenmedik çalışır. Bu yazıda hem sözdizimini hem bu üç sürprizi ele alacağım.
IF: kısa devre değerlendirme yok
IF kosul THEN
blok
ENDIF;
IF A > 1 && A < THIS.GETMAXVALUE(P1) THEN
RESULT = 'A bir ile maksimum değer arasında';
ENDIF;
Burada asıl kritik detay şu: TROIA, bir mantıksal ifadenin sonucu ilk koşuldan zaten belli olsa bile ifadenin tamamını değerlendirir. Yani C#, Java ya da JavaScript'te alışık olduğunuz "kısa devre" (short-circuit) davranışı burada yok. Pratikte bu şu anlama geliyor: A != NULL && A.ALAN > 0 gibi bir ifade yazarsanız ve A gerçekten null-benzeri bir durumdaysa, ikinci koşul yine de değerlendirilir — birçok dilde alışık olduğunuz "ilk koşul false ise ikincisine hiç bakılmaz, güvenlidir" varsayımı burada geçerli değil. Bir fonksiyon çağrısını güvenli hale getirmek için önce ayrı bir IF ile kontrol edip, güvenliyse iç içe ikinci bir IF yazmak gerekebilir.
ELSE var, ELSEIF yok
IF A == 1 THEN
RESULT = 'A bire eşit';
ELSE
RESULT = 'A birden farklı';
ENDIF;
TROIA'da ELSEIF desteklenmiyor; birden fazla koşulu sırayla test etmek istediğinizde ELSE bloğunun içine iç içe IF yazmanız gerekiyor:
IF DURUM == 'BEKLEMEDE' THEN
RESULT = 'Bekliyor';
ELSE
IF DURUM == 'ONAYLANDI' THEN
RESULT = 'Onaylandı';
ELSE
RESULT = 'Bilinmiyor';
ENDIF;
ENDIF;
Beş altı koşullu bir zincirde bu iç içelik hızla okunabilirliği düşürür — bu noktada SWITCH'e geçmek genelde daha temiz bir çözüm.
SWITCH: değişken şart, ifade yasak; BREAK gereksiz
SWITCH DEGISKEN
CASE 'deger1','deger2':
blok1
DEFAULT:
blok2
ENDSWITCH;
İki önemli kısıtlama var: SWITCH ifadesinin hedefi sadece bir değişken olabilir, bir ifade (expression) olamaz — yani SWITCH A + B yazamazsınız, önce sonucu bir değişkene atamanız gerekir. İkincisi, ve C ailesinden gelenler için asıl şaşırtıcı olan: BREAK anahtar kelimesi SWITCH içinde ne desteklenir ne de gereklidir — her CASE bloğu kendiliğinden sonlanır, C#'taki gibi bir sonraki case'e "düşme" (fall-through) davranışı yoktur.
VAR = '8';
SWITCH VAR
CASE '7','8':
RESULT = 'Yedi ya da sekiz';
DEFAULT:
RESULT = 'Ne olduğunu bilmiyorum.';
ENDSWITCH;
WHILE ve LOOP AT
WHILE kosul
BEGIN
blok
ENDWHILE;
SAYAC = 0;
WHILE SAYAC < 10
BEGIN
IF SAYAC % 2 == 0 THEN
RESULT = RESULT + SAYAC + ':çift, ';
ENDIF;
SAYAC = SAYAC + 1;
ENDWHILE;
Tablo satırları üzerinde gezinmek için ayrı bir komut var: LOOP AT {tablo} BEGIN ... ENDLOOP; — belgelerin kendi tabiriyle, şimdilik "satır bazlı bir foreach" olarak düşünülebilir (performans varyasyonlarını table-ve-loop-neden-bu-kadar-hizli yazısında ayrıca ele aldım).
BREAK ve CONTINUE
INDEKS = 0;
WHILE 1 == 1
BEGIN
INDEKS = INDEKS + 1;
IF INDEKS == 10 THEN
BREAK;
ENDIF;
IF INDEKS % 2 == 0 THEN
CONTINUE;
ENDIF;
/* burada sadece tek sayılar için çalışan kod */
ENDWHILE;
CONTINUE döngünün kalan kısmını atlayıp bir sonraki iterasyona geçer, BREAK döngüyü tamamen sonlandırır — bu ikisi TROIA'da diğer dillerdeki gibi tanıdık davranıyor; sürpriz olan kısım yukarıda bahsettiğim IF'in kısa devre yapmaması ve SWITCH'in BREAK istememesi.
Sık yapılan hatalar
- Kısa devre bekleyerek güvensiz bir ifade yazmak —
A != '' && FONKSIYON(A)gibi bir ifadedeFONKSIYON'un boşAile çağrılmasının güvenli olmadığını varsayıp bu tek satırı yazmak; TROIA'da ikisi de değerlendirileceği içinFONKSIYONher koşulda çağrılır. SWITCHiçineBREAKeklemeyi unutmamak diye endişelenmek — aslında endişelenecek bir şey yok,BREAKburada gereksiz; C#'tan gelenlerin refleks olarak eklediğiBREAK'ler burada anlam ifade etmez (hataya da yol açmaz, sadece gereksizdir).- Beş altı seviyeli iç içe
IF/ELSEyazıp okunabilirliği kaybetmek —ELSEIFolmadığı için bu tuzağa düşmek kolay; üç ya da daha fazla ayrık durum söz konusuysaSWITCH'e geçmek kodu belirgin şekilde sadeleştirir.
Sıradaki adım
Sıradaki yazıda dialog'ların BEFORE, AFTER, ONSHOW olaylarına ve CALL DIALOG ile ekranlar arası geçişe değineceğim.
Yorumlar (0)
Yorum Yaz