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

değişmez: [immutable], programın çalışması süresince kesinlikle değişmeyen
referans: [reference], asıl nesneye, onun takma ismi gibi erişim sağlayan program yapısı
sabit: [const], bir bağlamda değiştirilmeyen
sınıf: [class], kendi üzerinde kullanılan işlevleri de tanımlayan veri yapısı
üye işlev: [member function], yapı veya sınıfın kendi tanımladığı işlemleri
yapı: [struct], başka verileri bir araya getiren veri yapısı
... bütün sözlük



İngilizce Kaynaklar


Diğer




const ref Parametreler ve const Üye İşlevler

Bu bölümde üye işlevlerin immutable nesnelerle de kullanılabilmeleri için nasıl const olarak işaretlenmeleri gerektiğini göreceğiz. Bu bölümde her ne kadar yalnızca yapıları kullanıyor olsak da const üye işlevler sınıflar için de aynen geçerlidir.

immutable nesneler

Şimdiye kadarki bazı örneklerde immutable değişkenler ve nesneler tanımlamış ve immutable anahtar sözcüğünün nesnelerin değiştirilemez olmalarını sağladığını görmüştük:

    immutable okumaSaati = GününSaati(15, 0);

okumaSaati değiştirilemez:

    okumaSaati = GününSaati(16, 0);     // ← derleme HATASI
    okumaSaati.dakika += 10;            // ← derleme HATASI

Derleyici immutable nesneye yeni bir değer atanmasına veya bir üyesinin değiştirilmesine izin vermez. Zaten immutable olarak işaretlemenin amacı da budur: Bazı nesnelerin değerlerinin değişmemesi program doğruluğu açısından önemli olabilir.

const olmayan ref parametreler

Bu kavramı daha önce İşlev Parametreleri bölümünde görmüştük. ref parametrelerin işlev içinde değiştirilmemeleri yönünde bir kısıtlama yoktur. ref bir parametresini değiştirmiyor bile olsa, bunun garantisini vermediği için böyle bir işleve immutable nesne gönderilemez:

// süre'yi değiştirmediği halde const olarak işaretlenmemiş
int toplamSaniye(ref Süre süre) {
    return 60 * süre.dakika;
}
// ...
    immutable ısınmaSüresi = Süre(3);
    toplamSaniye(ısınmaSüresi);          // ← derleme HATASI

Derleyici immutable olan ısınmaSüresi nesnesinin toplamSaniye işlevine gönderilmesine izin vermez, çünkü toplamSaniye işlevi parametresinde değişiklik yapmayacağı garantisini vermemektedir.

const ref parametreler

const ref olarak işaretlenen bir parametre, o işlev içinde değiştirilmeyecek demektir:

int toplamSaniye(const ref Süre süre) {
    return 60 * süre.dakika;
}
// ...
    immutable ısınmaSüresi = Süre(3);
    toplamSaniye(ısınmaSüresi);          // ← şimdi derlenir

Parametresini const olarak işaretleyen işlev o parametrede değişiklik yapmayacağı garantisini vermiş olduğu için işleve immutable değişkenler de gönderilebilir.

Derleyici const parametrenin değiştirilmesine izin vermez:

int toplamSaniye(const ref Süre süre) {
    süre.dakika = 7;       // ← derleme HATASI
// ...
}

const ref yerine in ref de kullanılabilir. İlerideki bir bölümde göreceğimiz gibi, in parametrenin yalnızca giriş bilgisi olarak kullanıldığını ve bu yüzden değiştirilemeyeceğini bildirir:

int toplamSaniye(in ref Süre süre) {
    // ...
}
const olmayan üye işlevler

Nesneleri değiştirmenin başka bir yolu üye işlevlerdir. Bunu daha önce GününSaati.ekle işlevinde görmüştük. O üye işlev, üzerinde çağrıldığı nesneyi ona bir Süre ekleyerek değiştiriyordu:

struct GününSaati {
// ...
    void ekle(Süre süre) {
        dakika += süre.dakika;

        saat += dakika / 60;
        dakika %= 60;
        saat %= 24;
    }
// ...
}
// ...
    auto başlangıç = GününSaati(5, 30);
    başlangıç.ekle(Süre(30));          // başlangıç değişir
const üye işlevler

Bazı üye işlevler ise üzerinde çağrıldıkları nesnede değişiklik yapmazlar:

struct GününSaati {
// ...
    string toString() {
        return format("%02s:%02s", saat, dakika);
    }
// ...
}

toString'in tek işi nesneyi string olarak ifade etmektir ve zaten o kadar olmalıdır; nesnenin kendisini değiştirmez.

Üye işlevlerin nesnede bir değişiklik yapmayacakları garantisi parametre listesinden sonra yazılan const sözcüğü ile verilir:

struct GününSaati {
// ...
    string toString() const {
        return format("%02s:%02s", saat, dakika);
    }
}

O const, nesnenin o işlev içinde değiştirilmeyeceği anlamına gelir.

Böylece toString üye işlevi immutable nesneler üzerinde de çağrılabilir. Aksi halde nesnenin değiştirilmeyeceğinin garantisi bulunmadığından, immutable nesneler üzerinde çağrılamama gibi yapay bir kısıtlamayla karşı karşıya kalınırdı:

struct GününSaati {
// ...
    // const olarak işaretlenmemiş (yanlış tasarım)
    string toString() {
        return format("%02s:%02s", saat, dakika);
    }
}
// ...
    immutable başlangıç = GününSaati(5, 30);
    writeln(başlangıç);    // GününSaati.toString() çağrılmaz!

Çıktısı beklenendiği gibi 05:30 değil, derleyicinin çağırdığı genel bir işlevin çıktısıdır:

immutable(GününSaati)(5, 30)

toString immutable bir nesne üzerinde açıkça çağrıldığında ise bir derleme hatası oluşur:

    auto dizgiOlarak = başlangıç.toString(); // ← derleme HATASI

Bu açıdan bakıldığında şimdiye kadarki bölümlerde gördüğümüz toString üye işlevleri yanlış tasarlanmışlardır; aslında onların da const olarak işaretlenmeleri gerekirdi.

Not: İşlevin nesnede değişiklik yapmayacağını garanti eden const anahtar sözcüğü aslında işlevin tanımından önce de yazılabilir:

    // üsttekiyle aynı anlamda
    const string toString() {
        return format("%02s:%02s", saat, dakika);
    }

Öyle yazıldığında dönüş türüne aitmiş gibi yanlış bir anlam verebildiği için const anahtar sözcüğünü bu biçimde değil, daha yukarıda gösterildiği gibi parametre listesinden sonra yazmanızı öneririm.

inout üye işlevler

İşlev Parametreleri bölümünde gördüğümüz gibi, inout parametrenin değişmezlik bilgisini işlevin çıkış türüne aktarır.

Benzer biçimde, inout olarak tanımlanmış olan bir üye işlev de nesnenin değişmezlik bilgisini işlevin çıkış türüne aktarır:

import std.stdio;

struct Topluluk {
    int[] elemanlar;

    inout(int)[] başTarafı(size_t n) inout {
        return elemanlar[0 .. n];
    }
}

void main() {
    {
        // immutable bir Topluluk nesnesi
        auto topluluk = immutable(Topluluk)([ 1, 2, 3 ]);
        auto dilim = topluluk.başTarafı(2);
        writeln(typeof(dilim).stringof);
    }
    {
        // const bir Topluluk nesnesi
        auto topluluk = const(Topluluk)([ 1, 2, 3 ]);
        auto dilim = topluluk.başTarafı(2);
        writeln(typeof(dilim).stringof);
    }
    {
        // Değişebilen bir Topluluk nesnesi
        auto topluluk = Topluluk([ 1, 2, 3 ]);
        auto dilim = topluluk.başTarafı(2);
        writeln(typeof(dilim).stringof);
    }
}

Farklı değişmezliğe sahip üç nesnenin döndürdüğü üç dilim o nesnelerin değişmezliklerine sahiptir:

immutable(int)[]
const(int)[]
int[]

const ve immutable nesneler üzerinde de çağrılabilmeleri gerektiğinden inout üye işlevler derleyici tarafından const olarak derlenirler.

Ne zaman kullanmalı