IF Nedir, Nasıl Kullanılır

Created with Sketch.

IF Nedir, Nasıl Kullanılır

Merhaba,

Bu yazımızda IF kullanımı ile ilgili bazı tekniklerden bahsedeceğim. Bununla birlikte bu yazının içeriği PERFORMANS ODAKLI OLMAYACAK. Performans ile ilgili eleştiriler haklı da olabilir, haksız da olabilir o konuda yorum yapmıyorum. Yazının amacı, IF kullanım tekniklerinin çeşitliliğini göstererek dil ile kurduğumuz etkileşimin, kodlamada ve okunabilirlikte elde edeceğimiz faydalarından ve kod ile kurduğumuz bağdan yararlanmaya çalışmak olacak. Yazının devamında gösterilecek olan tekniklerin dikkatli kullanılmaması durumunda spagetti koda dönüşebileceği tehlikesinden de bahsetmeden edemeyiz. Tüm bunlardan önce mebzuya dalmadan, bir karar verme yapısının nasıl bir iskeleti olduğuna değinmemiz gerekecek. Sonrasında da gerek PHP’de, gerekse Transact SQL’de sıkça karşılaşmaya başladığımız inline IF tekniğini Delphi’de nasıl kullanabiliriz ve bu tekniği bir adım öteye nasıl taşıyabiliriz onun örneklerine bakacağız.

Karar Verme Yapıları dendiğinde, kabaca programcının, program tarafından sırası geldiğinde değerlendirilecek veya test edilecek olan herhangi bir durumun sorguladığı, ortaya konulan koşulun / şartın doğru olup olmadığının tespit edilmesi (veya edilmemesi) durumunda devreye girmesi için tasarlanan mekanizmaların kastediğildiğini anlamamız gerekir. Bu mekanizmaları kullanarak yazdığımız programlara (tabiri caizse bir çeşit) akıl katmış oluruz. İnsanları hayvanlardan ayıran en temel özelliklerden birisinin de karar almak olduğunu varsayarsak ilginçtir ki insanlarla makinalar arasındaki en temel ayrımın da bu olduğuna dikkat çekmekte fayda var.

Pascal Programlama Dili, Karar Verme Yapısı olarak “IF” ve “CASE” anahtar kelimelerini kullanır. Fakat kendi yazacağınız fonksiyonlarla da bu yapıları genişletebilir, çeşitlendirebilirsiniz. Standart karar verme yapılarının kendi içinde çeşitli kombinasyonları vardır. Kısaca bu yapılara bir göz atalım;

IF için en bilinen yapı “IF – THEN” yapısıdır. Örnek olarak aşağıdaki kodu inceleyebiliriz;

var
  a: Integer;
  S: String;
begin
  if (a > 100) then ShowMessage('100''den büyük');
  // veya
  if (S.Trim <> '') then ShowMessage('S, boş değil');
end;

Alternatif olarak “IF – THEN – ELSE” yapısıda kullanılabilir. Aşağıdaki örneğe bir göz atalım;

[img]https://i.hizliresim.com/MajQza.png[/img]

var
  a: Integer;
begin
  if (a > 100) THEN ShowMessage('100''den büyük') ELSE ShowMessage('100 veya daha altı');
end;

Ayrı bir alternatif olarak ardışık IF ELSE IF yapıları da kullanılabilir. Devamındaki örneği inceleyelim;

var
  a: Integer;
begin
  if (a <= 0) then ShowMessage('Negatif')
  ELSE 
  if (a > 50) then ShowMessage('100 veya daha altı') ;
end;

Veya aynı örneği begin / end blokları içine de alabiliriz. Yukarıdaki örneğin daha okunaklı alternatif bir sürümünü aşağıdaki kodu inceleyerek görebiliriz; Bu örneği, yukarıdakinden ayıran temel nitelik ise ilgili koşula birden çok direktifte bulunabilmemize olanak sağlamasıdır.

var
  a: Integer;
begin
  if (a <= 0) then begin
      ShowMessage('Negatif');
      //... ilgili diğer kodlar
  end else 
  if (a > 50) then begin
      ShowMessage('100 veya daha altı') ;
      //... ilgili diğer kodlar
  end;
end;

Bir kaç koşulun tek bir koşul gibi değerlendirilmesi gereken durumlar da olabilir;

var
  a: Integer;
  s: String;
begin
  a:= 32;
  if (  (a > 1) AND (a < 33)  ) then ShowMessage('a istenen aralıkta');
  s := 'JEST';
  if ( (a < 155) or (s = 'test') ) then ShowMessage('a 155''ten küçük veya s''in içeriği "test"');
end;

Bir değerin bir kümede olup olmadığına da bakılabilir;

var
  a: Integer;
  c: Char;
begin
  c := 'a';
  if c in [#0..#255] then ShowMessage('VAR') else ShowMessage('YOK');

  a := 4;
  if a in [1,4,5,3] then ShowMessage('a = ' + A.ToString) else ShowMessage('a, beklenen değerlerden herhangi birisine sahip değil');
end;

Bazı durumlarda ELSE’nin dikkatsiz kullanılması beklenmeyen sonuçlara neden olabilir. “IF THEN ELSE IF” yapısı ardışık kullanıldığında, yani bir CASE gibi kullanılmaya çalışıldığında derleyici, “karşılaşılan” ilk şartın doğru olması durumunda devamında gelen diğer şartların doğru olup olmadığına bakmaz ve doğrudan IF bloğunun sonuna dallanır. Bu davranışı anlamak için derleyicinin bir IF ifadesiyle karşılaştığında “tam olarak” neye baktığına bir göz atmak gerekir. Derleyici, IF ifadesinde geçen koşulun sonucunun “boolean” açısından “TRUE” olup olmadığına bakar. Yani siz koşul olarak her ne yazarsanız yazın, aslında derleyici o koşulun ikili sayı sistemindeki karşılığının 1 olup olmadığına bakar. Sonuç 1 ise koşulun doğru (TRUE) olduğuna karar verir ve hemen devamındaki kodları çalıştırır. Eğer sonuç 0 ise bu koşulun YANLIŞ (FALSE) olduğuna karar verir ve varsa “ELSE” ile ifade edilen kısma dallanır. Bundan sonrasında, IF ifadesi bir silsile izliyorsa, yani “IF THEN ELSE IF…” gibi birbirine bağlı bir kullanım söz konusu ise silsilenin devamına bakmaz ve doğrudan silsilenin en sonundaki END’e dallanır. 

Örneklendirmek gerekirse şöyle bir senaryo kurabiliriz;

begin
  if FALSE then begin
      ShowMessage('1');
  end else
  if TRUE then begin
      ShowMessage('2');
  end else
  if TRUE then begin
      ShowMessage('3');
  end else
  begin
      ShowMessage('4');
  end;
  // Bu örnekte sadece ShowMessage('2'); olan kısım çalışır. Devamında gelen koşullar doğru bile olsa IF komutu ifadenin en sonuna dallanır.
end;

Konuyu anlamak adına örnekleri biraz daha derinleştirmek gerekirse, derleyicinin bir IF komutuyla karşılaştığında özünde neye baktığını daha iyi anlamış oluruz.

var
  a: Integer;
begin
  if TRUE then ShowMessage('1) DOĞRU');

  // veya

  if False
     then ShowMessage('2) TRUE')
     else ShowMessage('2) FALSE');

  // veya

  if TRUE  then ShowMessage('3) TRUE')  else ShowMessage('3) NOT TRUE');
  if FALSE then ShowMessage('3) FALSE') else ShowMessage('3) NOT FALSE');

  // veya

  if 0 = 0 then begin
    ShowMessage('4) Sıfır eşittir sıfır');
  end else
  if 1 = 1 then begin
    // 1=1 koşulu doğru olduğu halde, yukarıdaki (0 = 0) koşulu derleyici açısından doğru olarak ilk karşılaşılan koşul olduğu için, derleyici bu kısmı görmezden gelir.
    ShowMessage('4) Bir eşittir bir (ama bu kısım hiç çalışmayacak...)');
  end;
end;

Yukarıda değindiğimiz özel durum, iç içe geçmiş (nested if) ifadeleri açısından soyutlanmıştır ve kendi skopları içinde değerlendirilir. Bunu biraz açmak gerekirse şöyle bir örnek konuyu anlamamız açısından yeterli olacaktır;

var
  a, b: Integer;
begin
  a := 50;
  b := a * 2;
  if (a = 50) then begin
      if ( b = (a * 2) ) then begin
           ShowMessage('B = 100 (Sadece bu kısım çalışır. diğerleri atıl kalacaktır.)');
      end else
      if ( a = (b div 2) ) then begin
           ShowMessage('Atıl kısım');
      end;
  END ELSE {< buraya dikkat edelim...}
  if (50 = a) then begin
      // dikkat ederseniz "a = 50" ile "50 = a" aslında aynı şey...
      // dolayısıyla bir önceki if koşulu doğru olduğu zaman asla bu kısma dallanmayacak.
      // o nedenle "END ELSE" ifadesini dikkatli kullanmak gerekir.
      ShowMessage('Atıl kısım');
  end;
end;

Bunun dışında NOT operatörü, öne sürdüğünüz koşulun tersini kullanmanıza olanak sağlar, mesela;

var
  a, b: Integer;
begin
  if (a <> 50) then ShowMessage('a, 50''ye eşit değildir...');
  // ile
  if NOT (a = 50) then ShowMessage('a, 50''ye eşit değildir...');
  // aynı şeyi ifade eder...

  // veya başka bir örnek daha verelim;
  if not false then ShowMessage('NOT FALSE = TRUE'); // gibi...
end;

Buraya kadar IF’in nasıl kullanıldığına bir göz attık. IF ifadesinin temel mekaniğini inceledik ve nelere dikkat etmemiz gerektiğini öğrendik. Değinecek, dokunacak başkaca ayrıntılar mutlaka vardır. Hatırladıkça bu makalenin devamına eklemeye devam edeceğim.

Yazının bundan sonraki kısmında ise tıpkı PHP ve T-SQL’deki gibi inline bir IIF fonksiyonunu Delphi’de nasıl tanımlanabileceğine ve bunu nasıl kullanabileceğimize bakacağız.

Özel bir IF fonksiyonu, Satıriçi IF kullanımı.

İki stringi bir koşula göre birleştirmek istediğimizde genelde aşağıdakine benzer bir yapı kullanırız;

function TeslimatMesaji(Ad: String; aCinsiyet: Boolean): String;
begin
  Result := 'Sayın ' + Ad + ' ';
  if aCinsiyet = TRUE then begin
      Result := Result + 'Bey,';
  end else begin
      Result := 'Hanım,';
  end;
  Result := Result + #13#10 + 'Talep ettiğiniz sipariş adresinize teslim edilmiştir.';
end;

Peki bu fonksiyonu şöyle yazsaydık daha anlaşılır ve sade olmaz mıydı?

function TeslimatMesaji(Ad: String; aCinsiyet: Boolean): String;
begin
  Result := 'Sayın ' + Ad + ' ' + IFF( aCinsiyet, 'Bey,', 'Hanım,') + #13#10 + 'Talep ettiğiniz sipariş adresinize teslim edilmiştir.' ;
end;

Her iki fonksiyon da temelde ve yöntemde aslında aynı şeyi yapıyor. Her ikisi de bir parametrenin değerini karşılaştırıyor, değerin doğru olup olmamasına göre belli bir içeriği sonuç kümesine işliyor. Burada, yazının performans odaklı olmadığından bahsetmiştik, yine bu konuya girmeyeceğiz. Bizim buradaki odak noktamız okunabilirik ve kod ile kurduğumuz anlam ilişkisinin basitliği ve anlaşılabilirliği olduğu için ben her zaman ikinci yöntemi tercih edenlerdenimdir. 

Örnek kodumuzda önizlemesini yaptığımız IFF fonksiyonunun yapısını incelemeye başlayalım isterseniz. Bu bir fonksiyon olması sebebiyle doğal olarak veri tiplerine bağımlı bir yapıya sahip olacaktır, o nedenle aynı mekanizmayı kurabilmek için bazı temel veri tipleriyle harmanlayıp overload etmemiz gerekecek. Ben, burada en sık kullandığım veri tipleri ve nesnelerden oluşam bir kolaj hazırladım ve aşağıda kullanımınıza sunuyorum; Bu arada, INDY bileşen paketinde yer alan ve IDGLOBAL.PAS dosyasında iif adı altında benzer fakat sayıca az olan fonksiyonlar da bulunmaktadır.

interface

uses
  System;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: String)   : String;    overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Integer)  : Integer;   overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: TDateTime): TDateTime; overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Boolean)  : Boolean;   overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Currency) : Currency;  overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: TObject)  : TObject;   overload;
function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Variant)  : Variant;   overload;

implementation

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: String): String;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Integer): Integer;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: TDateTime): TDateTime; overload;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Boolean): Boolean; overload;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Currency): Currency; overload;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: TObject): TObject; overload;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

function IFF(aKosul: Boolean; aDogruysa, aYanlissa: Variant): Variant; overload;
begin
  if aKosul then Result := aDogruysa else Result := aYanlissa;
end;

Yukarıdaki tüm IIF fonksiyonlarının kullanımı tamamen aynıdır. Hepsi için örnek kullanımı Özel bir if fonksiyonu, Satıriçi IF kullanımı. bölümünün 2. örneğinde görebilirsiniz. Bununla birlikte IFF fonksiyonunu iç içe veya ard arda da kullanabilirsiniz. Bu noktada size engel oluşturacak herhangi bir kullanım söz konusu değil. Tıpkı PHP’deki ve T-SQL”deki IIF gibi…

 

Yorum yapılmamış

Yorumunuzu ekleyin