Forum: D Programlama Dili RSS
Diziler referans olarak mı, değil mi?
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Diziler referans olarak mı, değil mi?
Daha dün dizilerin işlevlere referans olarak geçirildiklerini anlatan bir ders yazdıktan sonra şöyle bir deneme programı yazdım:

import std.cstream;
 
void değiştir(int[] dizi)
{
    dizi[0] = 1;
    dizi ~= 2;
 
    dout.writefln("İşlevde: ", dizi);
}
 
void main()
{
    int[] dizi = [ 0 ];
 
    dout.writefln("Önce   : ", dizi);
    değiştir(dizi);
    dout.writefln("Sonra  : ", dizi);
}

Çıktısı şöyle:

Önce   : [0]
İşlevde: [1,2]
Sonra  : [1]

Yani referans olarak geçtiği doğru, çünkü ilk elemanını değiştirebildik. Ama sonuna eklediğimiz elemanlar main'de görünmüyorlar. (?)

İngilizce forumda da bir soru açtım:

  http://www.digitalmars.com/webnews/newsgroups.…?art_grou…

Şimdi gidip Alexandrescu'nun kitabının diziler bölümünü okuyacağım. :)

Ali
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
(Not: Aşağıda yazılanlar dmd 2.036 üzerine...)

Diziler ve dilimler konusu şu anda D'nin en çok konuşulan konuları arasında.

Walter Bright ve Andrei Alexandrescu şu andaki tasarımının gayet iyi olduğunu savunuyorlar. Bartosz Milewski'nin de dahil olduğu başka bir çok kişi ise; ~= işlemi sonucunda dilimlerin birbirlerini hiç haber vermeden terkedebildikleri için çok hataya neden olacaklarını savunuyorlar.

Bu garip durumu yukarıdaki programda görüyoruz: işlev içindeki dizi, ~= işlemine kadar asıl dizinin elemanlarını paylaşmaya devam ediyor. O işlemden sonra ise dizi yeni bir yere taşındığı için artık asıl elemanlardan ayrılıyor.

Son tartışma şu:

  http://www.digitalmars.com/webnews/newsgroups.…?art_grou…

Ali
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Sabit uzunluklu diziler "değer türü", dinamik diziler "referans türü"
Bu konunun artık D2'de kapandığını kabul edebiliriz.

Dizi veri yapısı, D'ye C++'dan, ona da C'den geçmişti. Her iki dilde de diziler garip yaratıklardır. Örneğin başka her tür işlevlere kopyalanarak gönderildiği halde (yani bütün türler değer türü oldukları halde), diziler "ilk elemanlarını gösteren gösterge" olarak gönderilirler. Bu açıdan bakınca diziler C'de ve C++'da referans türüdürler.

Öte yandan, bir yapının üyesi olan bir dizi ise değer türüdür; çünkü yapı kopyalandığında veya atandığında içindeki dizi de kopyalanır.

Bu kavramlara D'de bir de dilim kavramı eklendiği için olaylar daha da karışıyordu.

Önce "Değerler ve Referanslar" dersinden

  http://ddili.org/ders/d/deger_referans.html

bir hatırlatma:

    * Değer türlerinden olan her değişkenin kendi değeri ve kendi adresi vardır
    * Referans türlerinden olan değişkenlerin kendi adresleri vardır; ama erişim sağladıkları değer kendilerinin değildir
    * Referans türlerinde atama işlemi değer değiştirmez, hangi asıl nesneye erişildiğini değiştirir
    * Referans türlerinden olan değişkenler null olabilirler

D2'de durum şu:

Sabit uzunluklu diziler değer türü

Bunun en ilginç sonucu, artık D2'de sabit uzunluklu diziler işlevlere kopyalanarak gönderiliyorlar.

void main()
{
    int[3] dizi1 = [ 7, 42, 100 ];
    auto dizi2 = dizi1;
 
    // Her dizi kendi elemanlarına sahip
    dizi1[0] = 777;
    assert(dizi2[0] == 7);
 
    // Sabit uzunluklu diziye eleman eklenemez
    // dizi1 ~= -1;  DERLEME HATASI
 
    // İşleve kopyalanarak gönderilir
    işlev(dizi1);
 
    // İşlevdeki değişiklik buradakini etkilemez
    assert(dizi1[0] == 777);
}
 
void işlev(int[3] dizi)
{
    // Yalnızca yerel kopyayı değiştirir
    dizi[0] = 888;
}

Dinamik diziler (dilimler) referans türü

Ben "dinamik dizi" ile "dilim"i dönüşümlü olarak kullanıyorum; çünkü teknik açıdan hiçbir farkları yok.

Bunlar kendi elemanlarına sahip değiller: ya var olan başka bir sabit uzunluklu dizinin elemanlarına erişim sağlıyorlar, ya da çöp toplayıcının sahip olduğu isimsiz bir dizinin elemanlarına...

Dinamik dizi kabul edilmesi için uzunluğu olmadan int[] diye tanımlanması gerekiyor.

Aşağıdaki kodda çok önemli bir nokta var. Eğer bir dinamik dizi başka dinamik dizi(ler)in de erişim sağladığı elemanlara erişim sağlıyorsa; yani eğer iki dizi aynı elemanları paylaşıyorlarsa; birisine eleman eklemek, asıl elemanların bu dizi için kopyalanmalarına, ve bu dizinin yeni elemanlara erişim sağlamasına neden olabilir. Diziye eleman eklemek, daha önceki paylaşımı sonlandırabilir.

Çok ilginç ve önemli bir konu... Yani .length ile, veya ~= ile dizinin boyunu büyülttüğümüzde, paylaşımın sonlandırılabileceği gibi böyle bir belirsizlik olduğunu akılda tutmak gerekiyor.

void main()
{
    int[] dizi1 = [ 7, 42, 100 ];
    auto dizi2 = dizi1;
 
    // İkisi de aynı elemana erişim sağlıyor
    dizi1[0] = 777;
    assert(dizi2[0] == 777);
 
    // Rahatça eleman eklenebilir
    foreach (i; 0 .. 100) {
        dizi1 ~= -1;
    }
    // AMA DİKKAT: Bu işlemin sonucunda dizi1 ile dizi2
    // arasındaki ilişki kesilebilir. Eskiden ortaklaşa erişim
    // sağladıkları elemanlar kopyalanır, ve dizi1 bu yeni
    // elemanlara erişim sağlamaya başlar.
    //
    // Artık aynı elemana erişim sağlamıyorlar:
    assert(&dizi1[0] != &dizi2[0]);
 
    // İşleve kopyalanarak gönderilir
    işlev(dizi1);
 
    // İşlevdeki değişiklik buradakini etkiliyor
    assert(dizi1[0] == 888);
}
 
void işlev(int[] dizi)
{
    // Dilim olduğu için, asıl elemanları etkiliyor
    dizi[0] = 888;
 
    // main'de olduğu gibi; eleman eklenince, yerel
    // dilim, yeni elemanlara erişim sağlamaya başlayabilir;
    // asıl elemanlara değil...
    foreach (i; 0 .. 200) {
        dizi ~= -2;
    }
 
    dizi[0] = 999;
    // 999 yapmış olmamıza rağmen, main içinde 888 ile
    // karşılaştıran assert hâlâ doğru çalışır
}

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-18, 17:22:34 (UTC -08:00)