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

atama: [assign], değişkene yeni bir değer vermek
ifade: [expression], programın değer oluşturan veya yan etki üreten bir bölümü
sağ değer: [rvalue], adresi alınamayan değer
sol değer: [lvalue], adresi alınabilen değer
... bütün sözlük



İngilizce Kaynaklar


Diğer




Sol Değerler ve Sağ Değerler

Her ifadenin değeri ya sol değerdir ya da sağ değerdir. Bu iki kavramı ayırt etmenin kolay bir yolu, dizi ve eşleme tablosu elemanları dahil olmak üzere bütün değişkenlerin sol değer, hazır değerler dahil olmak üzere bütün geçici değerlerin de sağ değer olduklarını kabul etmektir.

Örneğin, aşağıdaki writeln() çağrılarından birincisinin bütün parametreleri sol değerdir, ikincisindekiler ise sağ değerdir:

import std.stdio;

void main() {
    int i;
    immutable(int) imm;
    auto dizi = [ 1 ];
    auto tablo = [ 10 : "on" ];

    /* Aşağıdaki parametre değerlerinin hepsi sol değerdir. */

    writeln(i,             // değişken
            imm,           // immutable değişken
            dizi,          // dizi
            dizi[0],       // dizi elemanı
            tablo[10]);    // eşleme tablosu elemanı
                           // vs.

    enum mesaj = "merhaba";

    /* Aşağıdaki parametre değerlerinin hepsi sağ değerdir. */

    writeln(42,             // hazır değer
            mesaj,          // enum sabiti (manifest constant)
            i + 1,          // geçici değer
            hesapla(i));    // işlevin dönüş değeri
                            // vs.
}

int hesapla(int i) {
    return i * 2;
}
Sağ değerlerin yetersizlikleri

Sol değerlerle karşılaştırıldıklarında sağ değerler aşağıdaki üç konuda yetersizdir.

Sağ değerlerin adresleri yoktur

Sol değerlerin bellekte yerleri olabilir, sağ değerlerin olamaz.

Örneğin, aşağıdaki programdaki a + b sağ değerinin adresi alınamaz:

import std.stdio;

void main() {
    int a;
    int b;

    readf(" %s", &a);          // ← derlenir
    readf(" %s", &(a + b));    // ← derleme HATASI
}
Error: a + b is not an lvalue
Sağ değerlere yeni değer atanamaz

Değişmez olmadıkları sürece sol değerlere yeni değer atanabilir, sağ değerlere atanamaz.

    a = 1;          // ← derlenir
    (a + b) = 2;    // ← derleme HATASI
Error: a + b is not an lvalue
Sağ değerler işlevlere referans olarak geçirilemezler

Sol değerler referans olarak geçirilebilirler, sağ değerler geçirilemezler.

void onArttır(ref int değer) {
    değer += 10;
}

// ...

    onArttır(a);        // ← derlenir
    onArttır(a + b);    // ← derleme HATASI
Error: function deneme.onArttır (ref int değer)
is not callable using argument types (int)

Bu kısıtlamanın temel nedeni, işlevlerin referans türündeki parametrelerini sonradan kullanmak üzere bir kenara kaydedebilecekleri, oysa sağ değerlerin yaşamlarının sonradan kullanılmaya çalışıldıklarında çoktan sonlanmış olacağıdır.

C++ gibi bazı dillerden farklı olarak, D'de sağ değerler referansı const olarak alan işlevlere de geçirilemezler:

void yazdır(ref const(int) değer) {
    writeln(değer);
}

// ...

    yazdır(a);        // ← derlenir
    yazdır(a + b);    // ← derleme HATASI
Error: function deneme.yazdır (ref const(int) değer)
is not callable using argument types (int)
Hem sol değer hem sağ değer alabilen auto ref parametreler

Önceki bölümde gördüğümüz gibi, işlev şablonlarının auto ref parametreleri hem sol değer hem sağ değer alabilirler.

auto ref, bir sol değer ile çağrıldığında referans olarak geçirme anlamına gelir; sağ değer ile çağrıldığında ise kopyalayarak geçirme anlamına gelir. Derleyicinin bu farklı iki durum için farklı kod üretebilmesi için işlevin bir şablon olması gerekir.

Şablonları daha sonra göreceğiz. Şimdilik aşağıda işaretli olarak gösterilen boş parantezlerin onArttır'ı bir işlev şablonu haline getirdiğini kabul edin.

void onArttır()(auto ref int değer) {
    /* UYARI: Asıl parametre bir sağ değer ise buradaki
     * 'değer' adlı parametre çağıran taraftaki değerin
     * kopyasıdır. O yüzden, parametrede yapılan aşağıdaki
     * değişiklik çağıran tarafta gözlemlenemez. */

    değer += 10;
}

void main() {
    int a;
    int b;

    onArttır(a);        // ← sol değer; referans olarak geçirilir
    onArttır(a + b);    // ← sağ değer; kopyalanarak geçirilir
}

Yukarıdaki kod açıklamasında da belirtildiği gibi, parametrede yapılan değişiklik işlevi çağıran tarafta görülemeyebilir. O yüzden, auto ref genellikle parametrenin değişmediği durumlarda auto ref const olarak kullanılır.

Terimler

"Sol değer" ve "sağ değer" anlamına gelen "lvalue" ve "rvalue" ne yazık ki bu iki çeşit değeri yeterince ifade edemez. Başlarındaki l ve r harfleri "sol" anlamındaki "left"ten ve "sağ" anlamındaki "right"tan gelir. Bu sözcükler atama işlecinin sol ve sağ tarafını ifade ederler:

Bu terimlerin açık olmamalarının bir nedeni, hem sol değerlerin hem de sağ değerlerin aslında atama işlecinin her iki tarafında da yer alabilmeleridir:

    /* Bir sağ değer olan 'a + b' solda,
     * bir sol değer olan 'a' sağda: */
    array[a + b] = a;