D.ershane D Programlama Dili Dersleri

bayt sırası: [endianness], veriyi oluşturan baytların bellekte sıralanma düzeni
çokuzlu: [tuple], bir kaç parçanın diziye benzer şekilde bir araya gelmesinden oluşan yapı
gösterge: [pointer], bir değişkeni gösteren değişken
hata ayıklama: [debug], programın hatalarını bulma ve giderme
indeks: [index], topluluk elemanlarına erişmek için kullanılan bilgi
statik: [static], derleme zamanında belirli olan
sürüm: [version], programın, olanaklarına göre farklar içeren hali
... bütün sözlük

Bölümler
İngilizce Kaynaklar
Diğer



Koşullu Derleme

Programın bazı bölümlerinin belirli koşullara bağlı olarak farklı derlenmesi, veya hiç derlenmemesi istenebilir. D'nin koşullu derleme olanakları bu konuda kullanılır.

Derleme ile ilgili oldukları için, bu koşullar yalnızca derleme zamanında değerlendirilir; programın çalışması sırasında etkileri yoktur. Çalışma zamanında etkili olan if, for, while gibi D olanakları koşullu derleme olanakları değildir.

Aslında önceki derslerde koşullu derleme olarak kabul edilebilecek başka olanaklar görmüştük:

Yukarıdakiler, programın doğruluğunu arttırma amacına yönelik yardımcı olanaklar olarak görülebilir. Derleyici seçeneklerine bağlı olarak kullanılıp kullanılmamaları, programın asıl davranışını zaten değiştirmemelidir.

D'nin koşullu derlemeyi destekleyen ve bütünüyle bu amaç için tasarlanmış üç olanağı daha vardır:

debug

Program geliştirme aşamasında yararlı olan bir olanak debug belirtecidir. Bu belirteçle işaretlenmiş olan ifadeler ve bloklar yalnızca derleyicinin -debug seçeneği kullanıldığında etkilidir:

debug koşullu_derlenen_bir_ifade;

debug
{
    // ... koşullu derlenen ifadeler ...
}

Yukarıdaki tek ifade de, blok içindeki ifadeler de ancak -debug derleyici seçeneği etkin olduğunda derlenir.

Şimdiye kadarki programların hemen hemen hepsinde programın nasıl işlediğini gösteren "ekliyorum", "çıkartıyorum", gibi satırlar kullandık. Böylece algoritmaların işleyişlerini görsel bir hale getirerek olası hatalarını bulabiliyorduk. "debug", hata gidermek anlamına gelir ve bu konuda yararlıdır.

Bunun bir örneği olarak Şablonlar dersinde gördüğümüz ikiliAra işlevine bakalım. O algoritmanın açıklama satırlarını çıkartıyorum ve bilerek hatalı olarak yazıyorum:

import std.stdio;

// DİKKAT! Bu algoritma hatalıdır
int ikiliAra(const int[] değerler, in int değer)
{
    if (değerler.length == 0) {
        return -1;
    }

    const auto ortaNokta = değerler.length / 2;

    if (değer == değerler[ortaNokta]) {
        return ortaNokta;

    } else if (değer < değerler[ortaNokta]) {
        return ikiliAra(değerler[0 .. ortaNokta], değer);

    } else {
        return ikiliAra(değerler[ortaNokta + 1 .. $], değer);
    }
}

void main()
{
    int[] sayılar = [ -100, 0, 1, 2, 7, 10, 42, 365, 1000 ];

    int indeks = ikiliAra(sayılar, 42);
    writeln("Konum: ", indeks);
}

Yukarıdaki programı çalıştırdığımızda, 42'nin 6 olarak bildirilmesi gereken konumunun yanlış bildirildiğini görürüz:

Konum: 1

Bu hatayı bulmanın bir yolu, işlevin önemli noktalarına işlemler hakkında bilgiler veren satırlar eklemektir:

int ikiliAra(const int[] değerler, in int değer)
{
    writeln(değerler, " içinde ", değer, " arıyorum");

    if (değerler.length == 0) {
        writeln(değer, " bulunamadı");
        return -1;
    }

    const auto ortaNokta = değerler.length / 2;

    writeln("bakılan konum: ", ortaNokta);

    if (değer == değerler[ortaNokta]) {
        writeln(değer, ", ", ortaNokta, " konumunda bulundu");
        return ortaNokta;

    } else if (değer < değerler[ortaNokta]) {
        writeln("ilk yarıda olması gerek");
        return ikiliAra(değerler[0 .. ortaNokta], değer);

    } else {
        writeln("son yarıda olması gerek");
        return ikiliAra(değerler[ortaNokta + 1 .. $], değer);
    }
}

Programın şimdiki çıktısı, algoritmanın işleyiş adımlarını gösterir:

[-100,0,1,2,7,10,42,365,1000] içinde 42 arıyorum
bakılan konum: 4
son yarıda olması gerek
[10,42,365,1000] içinde 42 arıyorum
bakılan konum: 2
ilk yarıda olması gerek
[10,42] içinde 42 arıyorum
bakılan konum: 1
42, 1 konumunda bulundu
Konum: 1

Hatanın bu çıktıdan yararlanılarak bulunduğunu ve giderildiğini varsayalım. Hata giderildikten sonra artık writefln satırlarına gerek kalmaz ve hatta silinmeleri gerekir. Buna rağmen, o satırları silmek de bir israf olarak görülebilir; çünkü bugün silinirlerse, belki de ileride tekrar gerekebilirler.

Onun yerine, bu satırların başına debug anahtar sözcüğü yazılabilir:

        debug writeln(değer, " bulunamadı");

O satırlar artık yalnızca -debug derleyici seçeneği kullanıldığında etkin olacaktır:

dmd deneme.d -ofdeneme -w -debug

Böylece, programın normal işleyişi sırasında çıktıya hiçbir bilgi yazdırılmayacak; bir hata görüldüğünde ise -debug kullanılarak algoritmanın işleyişi hakkında bilgi alınabilecektir.

debug(isim)

debug belirtecinin çok yerde kullanılması durumunda programın çıktısı çok kalabalıklaşabilir. Böyle durumlarda debug belirteçlerine isimler verebilir ve onların yalnızca komut satırında belirtilenlerinin etkinleşmelerini sağlayabiliriz:

        debug(ikili_arama) writeln(değer, " bulunamadı");

İsimli debug belirteçlerini etkinleştirmek için komut satırında -debug=isim yazılır:

dmd deneme.d -ofdeneme -w -debug=ikili_arama

İsimli debug belirteçleri de birden fazla ifade için kullanılabilir:

    debug(ikili_arama)
    {
        // ... koşullu derlenen ifadeler ...
    }

Aynı anda birden çok isimli debug belirteci de kullanılabilir:

$ dmd deneme.d -ofdeneme -w -debug=ikili_arama -debug=yigin_yapisi

O durumda hem ikili_arama, hem de yigin_yapisi isimli debug blokları etkin olur.

debug(düzey)

Bazen debug belirteçlerine isimler vermek yerine, hata ayıklama düzeylerini belirleyen sayısal değerler verilebilir. Artan her düzey, daha derinlemesine bilgi verir:

debug import std.stdio;

void birİşlev(string dosyaİsmi, int[] sayılar)
{
    debug(1) writeln("birİşlev işlevine girildi");

    debug(2)
    {
        writeln("işlev parametreleri: ");
        writeln("  isim: ", dosyaİsmi);

        foreach (i, sayı; sayılar) {
            writefln("  %4s: %s", i, sayı);
        }
    }

    // ... asıl işlemler ...
}

Derleyiciye belirtilen debug düzeyi, o düzey ve daha düşük olanlarının etkinleşmesini sağlar:

$ dmd deneme.d -ofdeneme -w -debug=1
$ ./deneme 
birİşlev işlevine girildi

Daha derinlemesine bilgi almak istendiğinde:

$ dmd deneme.d -ofdeneme -w -debug=2
$ ./deneme 
birİşlev işlevine girildi
işlev parametreleri: 
  isim: deneme.txt
     0: 10
     1: 4
     2: 100
version(isim), ve version(düzey)

version, debug olanağına çok benzer ve kod içinde aynı şekilde kullanılır:

    version (denemeSürümü) /* ... bir ifade ... */;

    version (okulSürümü) {
        // ... okullara satılan sürümle ilgili ifadeler ...
    }

    version(1) birDeğişken = 5;

    version(2) {
        // ... sürüm 2 ile ilgili bir olanak ...
    }

Bütünüyle aynı şekilde çalışıyor olsa da, debug'dan farkı, program için farklı sürümler oluşturma amacıyla kullanılmasıdır.

Yine debug'da olduğu gibi, aynı anda birden fazla version bloğu etkinleştirilebilir:

$ dmd deneme.d -ofdeneme -w -version=kayit -version=hassas_hesap

Bazı version isimleri, programlarımızda yararlanabilmemiz için hazır olarak tanımlıdır:

Öntanımlı version belirteçleri
DigitalMars Derleyici, Digital Mars'ınki
X86 Intel veya AMD 32 bit işlemcisi
X86_64 AMD veya Intel 64 bit işlemcisi
Windows Microsoft Windows sistemi
Win32 Microsoft 32 bit Windows sistemi
Win64 Microsoft 64 bit Windows sistemi
linux Bütün Linux sistemleri
Posix Bütün Linux sistemleri
LittleEndian Bayt sırası; düşük değerlinin önce olduğu durum
BigEndian Bayt sırası; yüksek değerlinin önce olduğu durum
D_Coverage İşletilen bütün kod satırlarını belirleyecek şekilde derleniyor (Code coverage analysis, -cov derleyici seçeneği
D_Ddoc Ddoc belgeleri üretiliyor (-D derleyici seçeneği)
D_InlineAsm_X86 X86 inline assembler'ı mevcut
D_InlineAsm_X86_64 X86-64 inline assembler'ı mevcut
D_LP64 Göstergeler 64 bitlik (-m64 derleyici seçeneği)
D_PIC Position Independent Code üretiliyor (-fPIC derleyici seçeneği)
unittest Birim testleri etkin (-unittest derleyici seçeneği)
D_Version2 Bir D2 derleyicisi ile derlenmekte
none Hiçbir zaman tanımlı değildir; kod bloğunu etkisizleştirir
all Her zaman için tanımlıdır; none'ın tersidir

O tanımlardan yararlanarak programınızın farklı olanaklarla derlenmesini sağlayabilirsiniz. Kullanım örneği olarak std.string modülünde tanımlı olan newline'a bakalım:

version (Windows)
    immutable char[2] newline = "\r\n";
else version (Posix)
    immutable char[1] newline = "\n";

Satır sonu anlamına gelen kodları belirleyen newline dizisi, üzerinde derlenmekte olduğu işletim sistemine göre farklı olarak tanımlanmaktadır.

debug'a ve version'a isim atamak

debug ve version'a sanki bir değişkenmiş gibi isim atanabilir. Değişkenlerden farklı olarak, atama işlemi değer değiştirmez, değer olarak belirtilen debug veya version isminin de etkinleşmesini sağlar.

import std.stdio;

debug(hepsi)
{
    debug = 1;
    debug = 2;
    version = denemeSürümü;
    version = okulSürümü;
}

void main()
{
    debug(1) writeln("debug düzeyi 1");
    debug(2) writeln("debug düzeyi 2");

    version(denemeSürümü) writeln("deneme sürümü");
    version(okulSürümü) writeln("okul sürümü");
}

Yukarıdaki koddaki debug(hepsi) bloğu içindeki atamalar, her satırda belirtilen ismin de etkinleşmesini sağlar. Böylece bu program için derleme satırında dört debug ve version seçeneği farklı olarak seçilebileceği gibi, -debug=hepsi kullanıldığında; 1, 2, denemeSürümü, ve okulSürümü sanki komut satırında bildirilmişler gibi etkinleşir:

$ dmd deneme.d -ofdeneme -w -debug=hepsi
$ ./deneme 
debug düzeyi 1
debug düzeyi 2
deneme sürümü
okul sürümü
static if

Programın çalışması sırasındaki kararlarda çok kullandığımız if koşulunun derleme zamanındaki eşdeğeri static if'tir.

if koşulunda olduğu gibi, static if koşulu da bir mantıksal ifade ile kullanılır. static if bloğundaki kodlar bu mantıksal ifade true olduğunda derlenir ve programa dahil edilir, false olduğunda ise dahil edilmez. Yine if'e benzer şekilde, else static if ve else blokları da bulunabilir.

if'ten farklı olarak, mantıksal ifadenin sonucunun derleme zamanında bilinebiliyor olması şarttır.

static if her kapsamda kullanılabilir: modül dosyasında en üst düzeyde, yapı, sınıf, şablon, işlev, vs. kapsamlarında... Koşul sağlandığında, blok içindeki kodlar yazıldıkları satırda programa dahil edilirler.

Bir örnek olarak main içinde kullanalım:

import std.stdio;

void main()
{
    static if (char.sizeof == 1) {
        writeln("Merhaba dünya");

    } else static if (char.sizeof == 2) {
        writeln("Selam dünya");

    } else {
        writeln("Zaten beraberiz");
    }
}

char tek baytlık bir tür olduğu için, o program yalnızca "Merhaba dünya"lı satır yazılmış gibi derlenir:

import std.stdio;

void main()
{
    writeln("Merhaba dünya");
}

Çalışma zamanında hiçbir karşılaştırma yapılmaz.

static if zincirleri oluştururken else static if yazmak gerektiğine dikkat edin. Yanlışlıkla else if yazılmışsa, static if'in else bloğu olarak if kullanılacak demektir ve if de doğal olarak çalışma zamanında işletilecektir.

static if, çoğunlukla biraz aşağıda göreceğimiz is ifadesi ile kullanılır.

static assert

Aslında bir koşullu derleme olanağı olarak kabul edilmese de, static if'e benzerliği nedeniyle burada anlatmaya karar verdim.

Çalışma zamanında kullanmaya alıştığımız assert'le aynı şekilde, ama derleme zamanında işletilir. Mantıksal ifadesi false olduğunda derlemenin bir hata ile sonlandırılmasını sağlar.

static if gibi, static assert de programda herhangi bir kapsamda bulunabilir.

Örnek olarak, belirli bir algoritmanın yalnızca belirli büyüklükteki türlerle doğru olarak çalışabildiğini varsayalım. Bunu bir static assert ile şöyle denetleyebiliriz:

void birAlgoritma(T)(T değer)
{
    // Bu algoritma, büyüklüğü dördün katı olan türlerle
    // çalışabilir
    static assert((T.sizeof % 4) == 0);

    // ...
}

O işlev şablonu örneğin char ile çağrıldığında, programın derlenmesi bir hata ile sonlanır:

Error: static assert  (1u == 0u) is false

Böylece algoritmanın uygunsuz bir türle kullanılmasının ve olasılıkla hatalı çalışmasının önüne geçilmektedir.

static assert de aşağıdaki is ifadesinden yararlanabilir.

is ifadesi

Bu ifade, daha önce null değeri ve is işleci dersinde 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 koşula bağlı olarak 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 kendisinin 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 tek başına örnekler bulmak oldukça zor. Bunun şablon parametrelerinde yararlı olacağını düşünebilirsiniz:

    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ı şey
    } 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 dersinde gördüğümüz temel tür dönüşümlerini, veya Türeme dersinde 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'ten türemiş 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 işletilmektedir:

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 şu anahtar sözcükler kullanılabilir (bu anahtar sözcüklerden bazılarını daha sonraki derslerde anlatacağım):

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");
    }
}

Böylece; o işlev şablonu, çağrıldığı türe göre değişik davranacak şekilde kodlanabilir. 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);

    birİşlev(HaftaGünleri.Pazartesi);

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

    birİşlev(42);
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 tanımı
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ü
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: (in Object, in 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 (Tür isim : Belirteç, ŞablonParametreListesi)
is (Tür isim == Belirteç, ŞablonParametreListesi)

Bu iki kullanım, çok daha karmaşık ifadeler yazmaya olanak verir.

isim'den sonra kullanılan : ve == işleçleri, yukarıda gösterilen kullanımlarıyla aynı anlamdadır. Sırasıyla, o türe dönüşebilme ve aynı türden olma koşulunu denetlerler.

ŞablonParametreListesi, hem koşulun parçası olarak çalışır, hem de bütün koşul sağlandığında otomatik olarak uygun tür isimleri tanımlar. Bu, şablonlardaki tür çıkarsaması ile aynı şekilde çalışır.

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

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

Belirteç olarak Değer[İndeks] kullanılmış olması, şablon parametresi olan T'nin bir eşleme tablosu türü olmasını gerektirir. 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.

O koşulu kullanan ve dört farklı türle çağrılan bir program:

import std.stdio;

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

    static if (is (T Değer  : Değer[İndeks],
                     İ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ı

--- AssociativeArray!(string,int) ile çağrıldık ---
Evet, koşul sağlandı
değer türü : int
indeks türü: string

--- AssociativeArray!(string,double) ile çağrıldık ---
Evet, koşul sağlandı
değer türü : double
indeks türü: string

--- AssociativeArray!(long,dchar) ile çağrıldık ---
Hayır, koşul sağlanmadı