Thread overview
Diziler referans olarak mı, değil mi?
November 05, 2009

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.php?art_group=digitalmars.D&article_id=100151

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

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

November 24, 2009

(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.php?art_group=digitalmars.D&article_id=101153

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 07, 2010

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:

Alıntı:

>
* 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

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]