Thread overview
UFCS pointer üzerinden mi işler?
Jun 06, 2021
Salih Dincer
Jun 06, 2021
Ali Çehreli
Jun 07, 2021
Salih Dincer
Jun 07, 2021
Ali Çehreli
Jun 08, 2021
Salih Dincer
Jun 08, 2021
Ali Çehreli
Jun 08, 2021
Ali Çehreli
June 06, 2021

Merhaba,

Kod yazarken UFCS'nin esnekliğini seviyorum. Ama fazla mı esnek acaba? Çünkü bir sınıf içinden döndürülen bir dizge dilimlere ayrılıyorken, nedense köşeli parantezi iki şekilde de kabul ediyor:

import std.stdio;

class foo {
  string data;

  this(string str) {
    this.data = str;
    this.data.ptr.writeln;
    /* printOut: xxxxxxxxA0D2 */
  }

  auto bar() {
    string str  = data[0..3];
           str ~= data[3..$];
    return str;
  }
}

void main()
{
  auto test = new foo("result");

  test.bar.writeln(", ", &test.bar);
  /* printOut: result, string delegate() */

  test.bar[0..3].writeln(", ", test.bar.ptr);
  /* printOut: res, xxxxxxxx0030 */

  test.bar()[3..$].writeln(", ", test.bar().ptr);
  /* printOut: ult, xxxxxxxx0050 */
}

Tamam, yukarda sınıf kurulduktan sonra yapılan ilk denemede bunun dizge temsilcisi olduğunu görüyoruz; üstelik farklı ptr adresi dödürdüğünü de! Bence son yaptığım denemem, olması gereken çünkü ben sınıf içindeki (string data) dizgeyi doğrudan çağırmıyorum ki...

Ne dersiniz?

Teşekkürler...

June 06, 2021
On 6/6/21 2:04 PM, Salih Dincer wrote:

> Kod yazarken UFCS'nin esnekliğini seviyorum.

UFCS, modül düzeyinde yazılmış olan bir işlevin sanki üye işlevmiş gibi çağrılmasıdır. Burada modül düzeyinde işlev olmadığından UFCS diyemeyiz. Burada D'nin başka bir olanağını görüyoruz: Parametre almayan işlevlerin parantezsiz de çağrılabilmeleri. Sanırım buradaki konu bununla ilgili...

> Ama fazla mı esnek acaba?

Haklısın; karışıklık oluyor. test.bar deyince test'in bar işlevinden mi bahsediyoruz yoksa test'in bar işlevini çağırıyor muyuz?

> Çünkü bir sınıf içinden döndürülen bir dizge dilimlere ayrılıyorken,
> nedense köşeli parantezi iki şekilde de kabul ediyor:

Köşeli parantezlerin ilgisini henüz göremiyorum. Ama ~ veya ~= işleci uygulandığında yepyeni bir dizgi oluşacağını bekleyebiliriz. (Bazı durumlarda eniyileştirme sonucunda yeni bellek ayrılmaz.)

>
> ```d
> import std.stdio;
>
> class foo {
>    string data;
>
>    this(string str) {
>      this.data = str;
>      this.data.ptr.writeln;
>      /* printOut: xxxxxxxxA0D2 */
>    }
>
>    auto bar() {
>      string str  = data[0..3];
>             str ~= data[3..$];
>      return str;
>    }
> }
>
> void main()
> {
>    auto test = new foo("result");
>
>    test.bar.writeln(", ", &test.bar);
>    /* printOut: result, string delegate() */

Tamam: bar işlevini çağıracak olan bir 'delegate'.

>
>    test.bar[0..3].writeln(", ", test.bar.ptr);
>    /* printOut: res, xxxxxxxx0030 */

bar'ın döndürdüğü yeni dizginin karakterlerinin adresi.

>    test.bar()[3..$].writeln(", ", test.bar().ptr);
>    /* printOut: ult, xxxxxxxx0050 */

bar her çağrıldığında yeni bir dizgi oluşur. O yüzden farklı bir adres görüyoruz.

> }
> ```
>
> Tamam, yukarda sınıf kurulduktan sonra yapılan ilk denemede bunun dizge
> temsilcisi olduğunu görüyoruz; üstelik farklı ptr adresi dödürdüğünü de!
> Bence son yaptığım denemem, olması gereken çünkü ben sınıf içindeki
> (string data) dizgeyi doğrudan çağırmıyorum ki...
>
> Ne dersiniz?

Burada iki nokta var:

- &test.bar, bar'ı çağırmıyor.

- ~ ve ~= işleçleri yeni dizgi oluştururlar.

> Teşekkürler...

Rica ve tekrar hoşgeldin. :)

Ali


June 07, 2021
On Sunday, 6 June 2021 at 23:16:12 UTC, Ali Çehreli wrote:

> > (string data) dizgeyi doğrudan çağırmıyorum ki...
> >
> > Ne dersiniz?
>
> Burada iki nokta var:
>
> - &test.bar, bar'ı çağırmıyor.
>
> - ~ ve ~= işleçleri yeni dizgi oluştururlar.
>
> > Teşekkürler...
>
> Rica ve tekrar hoşgeldin. :)
>
> Ali

Hoş bulduk, peki cascade birleştirmede (bitwise işlemlerde complement) işaretini her kullanıldığımızda belleğin başka bir bölgesinde yeni bir dizgi mi oluşur acaba...

Yani diyelim ki 16 rasgele üretilmiş rakamı bir dizgide ardı ardına birleştirip büyük bir sayıyı (tabii ki metin formunda) oluşturduğumuzda her seferinde ve toplamda 15 defa yeni bir yere mi taşınıyor?

Görünüşe göre (aşağıdaki kod derlenediğinde) öyleymiş!

```
  import std.format, std.random;

  string str = "1";
  str.ptr.writeln(": ", str);

  int r = 1;
  foreach(i; 1..16)
  {
    auto rnd = Random(r * i);
    r = uniform(0, 10, rnd);
    str ~= format!"%s"(r);
  }
  str.ptr.writeln(": ", str);
  /*
    printOut:
      564B772750F1: 1
      7F5FB92D71E0: 1573323345424927
  */
```
June 07, 2021
On 6/6/21 10:55 PM, Salih Dincer wrote:

> peki cascade birleştirmede (bitwise işlemlerde complement)
> işaretini her kullanıldığımızda belleğin başka bir bölgesinde yeni bir
> dizgi mi oluşur acaba...

Öyle olacağını beklemek zorundayız ama bazı durumlarda eniyileştirmeler olacaktır. Ancak, ekleme (a ~= b) ve birleştirme (a ~ b) farklıdır: Eklemede en iyileştirmeler olacaktır ama birleştirmede yeni dizgi oluşturulur.

Bir ekleme örneği de benden:

import std.stdio;

void main() {
  int[] dizi;
  auto bilinenYer = dizi.ptr;
  foreach (i; 0 .. 100) {
    dizi ~= i;
    if (dizi.ptr != bilinenYer) {
      writefln!"%3s ekleyince kopyalandı: %s -> %s "(i, bilinenYer, dizi.ptr);
      bilinenYer = dizi.ptr;
    }
  }
}

  0 ekleyince kopyalandı: null -> 7F804A452000
  3 ekleyince kopyalandı: 7F804A452000 -> 7F804A453000
  7 ekleyince kopyalandı: 7F804A453000 -> 7F804A454000
 11 ekleyince kopyalandı: 7F804A454000 -> 7F804A455000
 15 ekleyince kopyalandı: 7F804A455000 -> 7F804A456000
 23 ekleyince kopyalandı: 7F804A456000 -> 7F804A457000
 31 ekleyince kopyalandı: 7F804A457000 -> 7F804A458000
 43 ekleyince kopyalandı: 7F804A458000 -> 7F804A459000
 63 ekleyince kopyalandı: 7F804A459000 -> 7F804A45A000
 91 ekleyince kopyalandı: 7F804A45A000 -> 7F804A45B000


Görüldüğü gibi, ancak bazen bellek ayrılıyor. Hem de kapasite, başka gerçekleştirmelerden bekleyebileceğimiz gibi %100, %50, vs. gibi bilinen değerlerle artmıyor. Çöp toplayıcı, diziye ait olmayan ama hemen sonrasındaki yerin boş olduğunu gördüğünde hızlıca o yeri de bu diziye veriyor.

Eğer bu dizinin arkasındaki yer kullanımda olsaydı (hatta bir olasılıkla bu "dizi" başka bir dizinin dilimi olsaydı), o zaman yer ayrılırdı.

Ali


June 08, 2021
Çok güzel bir örnek ve sanırım GC'ye emanet bir durum...

Çünkü güncel sürüm ama farklı birçok makinede aynı sonucu (elbette bellek adresleri dışında) elde ettim. Sonra sistemin yönetim yetkisi bana ait olan 64 bit sisteme 2.076.0 sürümünü yükledim. Derlediğimde ise çok farklı şu sonucu elde ettim:
```
C:\DLANG2076>bs
  0 KOPYALANDI: null -> 21B1010
  3 KOPYALANDI: 21B1010 -> 21B2000
  7 KOPYALANDI: 21B2000 -> 21B3000
 15 KOPYALANDI: 21B3000 -> 21B0080
 31 KOPYALANDI: 21B0080 -> 21B4000
 63 KOPYALANDI: 21B4000 -> 21B5000
```

Fark ettiyseniz 2 üzeri 2 - 6 arasında bellek ayırma tettiklemesi var. Yani döngüyü 130'a çıkarsaydık 127'de de benzer bir durum olacaktı.

Eminim 2 sürüm arasında GC'de önemli bir farklılığa ve/veya akıllıca bir çözüme gidilmiş. Aslında alt sürümler 2018 yılı: .83 ve 2020 yılı .92'de denediğimde günümüz güncel sürümü ile aynı sonucu elde ediyoruz.

Ali hocam sizin sürüm de .76'dan sonra olsa gerek?

June 08, 2021
On 6/8/21 3:10 AM, Salih Dincer wrote:

> sizin sürüm de .76'dan sonra olsa gerek?

Ben fazla geri kalmamaya dikkat ediyorum. Şu andaki sürüm olan 2.097.1'i kullanmıştım.

Yakın zaman önce çıkan sürümlerle gelen bir değişiklik de çöp toplayıcının belleği "multi-threaded" olarak taraması. Fazla ümitlenmeyelim: Programın bütün iş parçacıkları yine de durduruluyor ama kullanımda olan yerlerin belirlenmesi işi, GC'nin birden fazla iş parçacığı ile hallediliyor. Yani, bazı küçük gelişmeler oluyor.

Ali


June 08, 2021
On 6/8/21 8:43 AM, Ali Çehreli wrote:

> Şu andaki sürüm olan 2.097.1'i

Karıştırmışım: Şirkette 2.096.1'i kullanıyoruz ama şimdiki sürüm 2.097.0 (kendi bilgisayarımda).

Ali