D Programlama Dili – Programlama dersleri ve D referansı
Ali Çehreli

statik: [static], derleme zamanında belirli olan
... bütün sözlük



İngilizce Kaynaklar


Diğer




is İfadesi

Bu ifade, daha önce null değeri ve is işleci bölümünde gördüğümüz is işlecinden anlam ve yazım açısından farklıdır:

    a is b            // daha önce gördüğümüz is işleci
    is (/* ... */)    // is ifadesi

Bu bölümün konusu olan is ifadesi derleme zamanında işletilir ve parantez içindeki ifadeye bağlı olan bir değer üretir. Ürettiği değerin türü int'tir; koşul geçerli olduğunda 1, geçersiz olduğunda 0 değerini alır.

is'in aldığı koşul bir mantıksal ifade değildir ama is'in kendi değeri bir mantıksal ifadede kullanılmaya elverişlidir. Örneğin if deyimiyle, ve derleme zamanında işletildiği için daha da uygun olarak static if deyimiyle kullanılabilir.

Aldığı koşul türlerle ilgilidir ve bir kaç özel biçimden birisi olarak yazılmak zorundadır. En çok şablon parametrelerini denetlemede ve şablon parametre türleriyle ilgili bilgi toplamada yararlıdır.

is (Tür)

Tür'ün anlamsal olarak geçerli bir tür olup olmadığını denetler.

is'in bu kullanımı için bu noktada tek başına örnekler bulmak oldukça zor. Bunun yararını daha sonraki bölümlerde şablon parametreleri ile kullanırken göreceğiz.

    static if (is (int)) {
        writeln("geçerli");

    } else {
        writeln("geçersiz");
    }

Yukarıdaki koşulda kullanılan int, geçerli bir türdür:

geçerli

Başka bir örnek olarak, eşleme tablosu indeks türü olarak void kullanmak geçersiz olduğu için bu örnekte else bloğu işletilir:

    static if (is (string[void])) {
        writeln("geçerli");

    } else {
        writeln("geçersiz");
    }
geçersiz
is (Tür Takmaİsim)

Yukarıdaki ile aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda Takmaİsim'i türün yeni takma ismi olarak tanımlar:

    static if (is (int Yeniİsim)) {
        writeln("geçerli");
        Yeniİsim değişken = 42; // int ve Yeniİsim aynı anlamda

    } else {
        writeln("geçersiz");
    }

Takma ismin bu şekilde is ifadesinin içinde tanımlanabilmesi, daha sonra göreceğimiz karmaşık is ifadelerinde yararlıdır.

is (Tür : ÖzelTür)

Tür'ün belirtilen özel türe otomatik olarak dönüşüp dönüşemediğini denetler.

Tür Dönüşümleri bölümünde gördüğümüz temel tür dönüşümlerini, veya Türeme bölümünde gördüğümüz "bu alt sınıf, o üst sınıfın türündendir" ilişkilerini denetlemede kullanılır.

import std.stdio;

interface Saat {
    void zamanıOku();
}

class ÇalarSaat : Saat {
    override void zamanıOku() {
        writeln("10:00");
    }
}

void birİşlev(T)(T nesne) {
    static if (is (T : Saat)) {
        // Eğer buraya geldiysek, şablon parametresi olan T
        // Saat yerine kullanılabilen bir türdür
        writeln("bu bir Saat; zamanı söyleyebiliriz");
        nesne.zamanıOku();

    } else {
        writeln("bu bir Saat değil");
    }
}

void main() {
    auto değişken = new ÇalarSaat;
    birİşlev(değişken);
    birİşlev(42);
}

O kod, birİşlev şablonu Saat'e dönüşebilen bir tür ile çağrıldığında nesne'nin zamanıOku işlevini de çağırmaktadır. Tür int olduğunda ise else bloğu derlenmektedir:

bu bir Saat; zamanı söyleyebiliriz     ← ÇalarSaat için
10:00                                  ← ÇalarSaat için
bu bir Saat değil                      ← int için
is (Tür Takmaİsim : ÖzelTür)

Yukarıdakiyle aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda Takmaİsim'i koşulu sağlayan türün yeni takma ismi olarak tanımlar.

is (Tür == ÖzelTür)

Tür'ün belirtilen özel türün aynısı olup olmadığını, veya aynı belirtece sahip olup olmadığını denetler.

Aynı tür anlamında

Yukarıdaki örnek kodu değiştirsek ve : yerine == kullansak, bu sefer ÇalarSaat için de geçersiz olacaktır:

    static if (is (T == Saat)) {
        writeln("bu bir Saat; zamanı söyleyebiliriz");
        nesne.zamanıOku();

    } else {
        writeln("bu bir Saat değil");
    }

ÇalarSaat Saat'ten türediği için bir Saat'tir, ama Saat'in aynısı değildir. O yüzden koşul hem ÇalarSaat için, hem de int için geçersizdir:

bu bir Saat değil
bu bir Saat değil
Aynı belirtece sahip anlamında

ÖzelTür yerine bir belirteç kullanıldığında türün o belirtece uyup uymadığını denetler. Bu kullanımda belirteç olarak aşağıdaki anahtar sözcükler kullanılabilir (bu sözcüklerden bazılarını daha sonraki bölümlerde göreceğiz):

void birİşlev(T)(T nesne) {
    static if (is (T == class)) {
        writeln("bu bir sınıf türü");

    } else static if (is (T == enum)) {
        writeln("bu bir enum");

    } else static if (is (T == const)) {
        writeln("bu 'const' bir tür");

    } else {
        writeln("bu başka bir tür");
    }
}

İşlev şablonları çağrıldıkları türe göre değişik davranacak şekilde kodlanabilirler. Koşulun değişik bloklarının etkinleştiğini göstermek için şöyle deneyebiliriz:

    auto değişken = new ÇalarSaat;
    birİşlev(değişken);

    // (enum HaftaGünleri biraz aşağıda tanımlanıyor)
    birİşlev(HaftaGünleri.Pazartesi);

    const double sayı = 1.2;
    birİşlev(sayı);

    birİşlev(42);

Çıktısı:

bu bir sınıf türü
bu bir enum
bu 'const' bir tür
bu başka bir tür
is (Tür isim == Belirteç)

Yukarıdaki ile aynı şekilde çalışır. Ek olarak, koşul geçerli olduğunda isim'i duruma göre farklı anlamlarda tanımlar. isim, yukarıdaki takma isimli kullanımlardaki gibi doğrudan türün takma ismi olabileceği gibi, belirtece bağlı olarak başka bir bilgi de olabilir:

Belirteç isim'in anlamı
struct koşulu sağlayan tür
union koşulu sağlayan tür
class koşulu sağlayan tür
interface koşulu sağlayan tür
super üst tür ve arayüzlerden oluşan çokuzlu
enum enum'un gerçekleştirildiği temel tür
function işlev parametrelerinden oluşan çokuzlu
delegate delegate'in türü
return işlevin, delegate'in, veya işlev göstergesinin dönüş türü
__parameters işlevin, delegate'in, veya işlev göstergesinin parametrelerinden oluşan çokuzlu
const koşulu sağlayan tür
immutable koşulu sağlayan tür
shared koşulu sağlayan tür

Bu olanağın nasıl çalıştığını göstermek için önce bazı türler tanımlayalım:

struct Nokta {
    // ...
}

interface Saat {
    // ...
}

class ÇalarSaat : Saat {
    // ...
}

enum HaftaGünleri {
    Pazartesi, Salı, Çarşamba, Perşembe, Cuma,
    Cumartesi, Pazar
}

char foo(double kesirli, int tamsayı, Saat saat) {
    return 'a';
}

is ifadesinin bu değişik türlerle kullanımlarını göstermek için aşağıdaki gibi bir işlev şablonu yazılabilir. İşlevin çağrıldığı türlerin, nesnelerin, ve isim'in ne anlamlara geldiklerini açıklama satırları olarak yazdım:

void birİşlev(T)(T nesne) {
    static if (is (T YerelTür == struct)) {
        writefln("\n--- struct ---");
        // T ve YerelTür aynı anlamdadır; 'nesne', bu işleve
        // gelen yapı nesnesidir

        writeln("Yeni bir ", YerelTür.stringof,
                " nesnesini kopyalayarak oluşturuyorum");
        YerelTür yeniNesne = nesne;
    }

    static if (is (T üstTürler == super)) {
        writeln("\n--- super ---");
        // 'üstTürler' çokuzlusu bütün üst türleri içerir;
        // 'nesne', bu işleve gelen sınıf nesnesidir

        writeln(T.stringof, " sınıfının ", üstTürler.length,
                " adet üst türü var");

        writeln("hepsi birden: ", üstTürler.stringof);
        writeln("en üstteki: ", üstTürler[0].stringof);
    }

    static if (is (T AsılTür == enum)) {
        writeln("\n--- enum ---");
        // 'AsılTür', enum değerlerini gerçekleştirmek için
        // kullanılan asıl türdür; 'nesne', bu işleve gelen
        // enum değeridir

        writeln(T.stringof, " enum türü, perde arkasında ",
                AsılTür.stringof,
                " olarak gerçekleştirilmiştir");
    }

    static if (is (T DönüşTürü == return)) {
        writeln("\n--- return ---");
        // 'DönüşTürü', işlevin dönüş türüdür; bu işleve
        // parametre olarak gelen 'nesne', bir işlev
        // göstergesidir

        writeln("Bu, dönüş türü ", DönüşTürü.stringof,
                " olan bir işlev:");
        writeln("  ", T.stringof);
        write("çağırıyoruz... ");

        // Not: İşlev göstergeleri işlev gibi çağrılabilirler
        DönüşTürü sonuç = nesne(1.5, 42, new ÇalarSaat);
        writeln("ve sonuç: ", sonuç);
    }
}

O işlevi yukarıdaki farklı türlerle şöyle çağırabiliriz:

    // Yapı nesnesiyle
    birİşlev(Nokta());

    // Sınıf nesnesiyle
    birİşlev(new ÇalarSaat);

    // enum değerle
    birİşlev(HaftaGünleri.Pazartesi);

    // İşlev göstergesiyle
    birİşlev(&foo);

Çıktısı:

--- struct ---
Yeni bir Nokta nesnesini kopyalayarak oluşturuyorum

--- super ---
ÇalarSaat sınıfının 2 adet üst türü var
hepsi birden: (Object, Saat)
en üstteki: Object

--- enum ---
HaftaGünleri enum türü, perde arkasında int olarak
gerçekleştirilmiştir

--- return ---
Bu, dönüş türü char olan bir işlev:
  char function(double kesirli, int tamsayı, Saat saat)
çağırıyoruz... ve sonuç: a
is (/* ... */ Belirteç, ŞablonParametreListesi)

Şablon parametre listesi içeren is ifadesinin dört farklı kullanımı vardır:

Bu dört kullanım çok daha karmaşık ifadeler yazmaya olanak verir.

isim, Belirteç, :, ve == hep yukarıdaki kullanımlarıyla aynı anlamdadırlar.

ŞablonParametreListesi ise hem koşulun parçası olarak işlem görür hem de bütün koşul sağlandığında otomatik olarak uygun tür isimleri tanımlamaya yarar. Şablonların tür çıkarsama olanağı ile aynı biçimde işler.

Örnek olarak, indeks değeri string olan eşleme tabloları kullanıldığında özel işlemler yapılması gereksin. Yalnızca böyle türlere uymaya çalışan bir is ifadesi şöyle yazılabilir:

    static if (is (T == Değer[İndeks],    // (1)
                   Değer,                 // (2)
                   İndeks : string)) {    // (3)

O koşulu üç bölüm olarak açıklayabiliriz. Bunların son ikisi ŞablonParametreListesi'ni oluşturmaktadır:

  1. T, Değer[İndeks] yazımına uygunsa
  2. Değer herhangi bir tür ise
  3. İndeks bir string ise (şablon özellemesi söz dizimi)

Belirteç olarak Değer[İndeks] kullanılmış olması şablon parametresi olan T'nin bir eşleme tablosu türü olmasını gerektirir. Değer için hiçbir koşul belirtilmemiş olması onun herhangi bir tür olmasının yeterli olduğu anlamına gelir. Ek olarak, eşleme tablosunun indeks türünün de özellikle string olması gerekmektedir. Dolayısıyla, yukarıdaki is ifadesi, "T, indeks türü string olan bir eşleme tablosu ise" anlamına gelmektedir.

Bu is ifadesini kullanan ve dört farklı türle çağrılan bir örnek şöyle yazılabilir:

import std.stdio;

void birİşlev(T)(T nesne) {
    writeln("\n--- ", T.stringof, " ile çağrıldık ---");

    static if (is (T == Değer[İndeks],
                   Değer,
                   İndeks : string)) {

        writeln("Evet, koşul sağlandı.");

        writeln("değer türü : ", Değer.stringof);
        writeln("indeks türü: ", İndeks.stringof);

    } else {
        writeln("Hayır, koşul sağlanmadı.");
    }
}

void main() {
    int sayı;
    birİşlev(sayı);

    int[string] intTablosu;
    birİşlev(intTablosu);

    double[string] doubleTablosu;
    birİşlev(doubleTablosu);

    dchar[long] dcharTablosu;
    birİşlev(dcharTablosu);
}

Koşul, yalnızca indeks türü string olan eşleme tabloları için sağlanmaktadır:

--- int ile çağrıldık ---
Hayır, koşul sağlanmadı.

--- int[string] ile çağrıldık ---
Evet, koşul sağlandı.
değer türü : int
indeks türü: string

--- double[string] ile çağrıldık ---
Evet, koşul sağlandı.
değer türü : double
indeks türü: string

--- dchar[long] ile çağrıldık ---
Hayır, koşul sağlanmadı.