Thread overview
CircularList: Dairesel Kuyruk Yapısı
Feb 19, 2023
Salih Dincer
Feb 20, 2023
Ali Çehreli
Feb 27, 2023
Salih Dincer
Feb 27, 2023
Ali Çehreli
Feb 28, 2023
Salih Dincer
Feb 27, 2023
Salih Dincer
Feb 28, 2023
Salih Dincer
February 19, 2023

Merhaba,

Geçen hafta çok temel olan dizgeler için, çok da gereksiz bir sarmalayıcı yazmıştık ama bugün daha da temel olan ve Türkçe bağlı liste olarak çevrilen konuya girelim dedim. Hem de en en basitinden ve dairesel bir açıyla dalış yapacağız! Buna eski ile yeninin (D ranges) buluşması adını veriyorum:

Koda buyrun, balıklamasına... 😀

struct CircularList(Node) // v1.1 for D Class
{
  private Node items, root;
  size_t length;

  string toString() const {
    import std.format: format;
    return format("CircularList(%s[%s], %s)",
                  Type.stringof, length, root);
  }
  alias Type = typeof(Node.CLL);
  void push(Type value) {
    if(isEmpty) {
      items = new Node(value, null);
      root = items;
    } else {
      items.link = new Node(value, root);
      popFront();
    }
    ++length;
  }
  auto isEmpty() {
    return !items;
  }
  /********************** Input Range Functions */
  enum empty = false;
  auto front() { return items.link.CLL; }
  void popFront() { items = items.link; }
  /*                (InputRange)                */
}

Bugün şu başlığa denk geldim, bu işler bu kadar zor olmamalı dedim kendi kendime. Önce UniversalAdaptor ve sonrası daha da basit olan CircularList ortaya çıktı. Eğer kendi türünüze CLL takma ismi ve link işaretçisi (dikkat, sınıflar referans türü olduğu için * işareti kullanmadım) dahil ederseniz, bunu basitçe kullanabilirsiniz. Örneğin MyString sınıfı için bu kadar basit:

class MyString
{ // Circular Linked List --v
  string data;       alias CLL = data;
                     MyString link;
  this(string s,     MyString n = null) {
    data = s;
    link = n;
  }
// ...

Tabi Node olarak bildirilen tür bir yapı olsaydı açık bir şekilde * işareti kullanmanız gerekiyor. Onun da çözümü kısmen şu (v1.2) olabilir:

struct CircularList(Node) // v1.2 for D
{
  static if(is(Node == struct))
  {
    private Node * items, root;
  }
  else static if(is(Node == class))
  {
    private Node items, root;
  }
  else static assert(0, "\nIt's not a container!");
//..

Tam burada Ali hocama bir soru:

Kodu, static if'ler (sadece class ve struct) ile kısıtladığımızda, derleyici önce alias'ların token'nını çözdüğü için şu test assert'e uğramıyor:

void main() {
  enum Test { none }
  CircularList!Test itsnotacontainer;
}

Ama bu testi başarıyla, yani hata mesajıyla geçiyor:

void main() {
  enum Test { CLL }
  CircularList!Test itsnotacontainer;
}

Neyse, kodları parça parça verdim ama merak edenler, class/struct ayırt edilmeksizin şöyle çalıştırabilir:

struct CircularList(Node) // v1.2 for D
{
  static if(is(Node == struct))
  {
    private Node * items, root;
  }
  else static if(is(Node == class))
  {
    private Node items, root;
  }
  else static assert(0, "\nIt's not a container!");
  size_t length;

  string toString() const
  {
    import std.format: format;
    return format("CircularList(%s[%s], %s)",
                  Type.stringof, length, root);
  }
  alias Type = typeof(Node.CLL);
  void push(Type value)
  {
    if(isEmpty)
    {
      items = new Node(value, null);
      root = items;
    }
    else
    {
      items.link = new Node(value, root);
      popFront();
    }
    ++length;
  }
  auto isEmpty()
  {
    return !items;
  }
  /********************** Input Range Functions */
  enum empty = false;
  auto front() { return items.link.CLL; }
  void popFront() { items = items.link; }
  /*                (InputRange)                */
}

class Bar
{
  size_t number; alias CLL = number;
  Bar link;

  this(size_t number, Bar link = null)
  {
    this.number = number;
    this.link = link;
  }
}

struct Foo
{
  size_t number; alias CLL = number;
  Foo * link = null;
}

void main()
{
  CircularList!Bar bar;
  CircularList!Foo foo;

  foreach(n; 10..16)
  {
    bar.push(n);
    foo.push(n);
  }

  import std.range : take;
  import std.stdio : writeln;

  bar.take(8).writeln(": ", bar);
  foo.take(8).writeln(": ", foo);
}

Geçen haftaki örnek MyString için ise şöyle:

void main() {
  auto merhaba = new MS("Merhaba");
  auto sana = new MS("sana");
  auto ey = new MS("ey");
  auto kelimeler = [ merhaba, sana, ey ];

  CircularList!MS test;
  foreach(kelime; kelimeler)
  {
    kelime ~= " ";/*
    kelime.writeln;//*/
    test.push(kelime.data);
  }
  test.take(5).writeln;
} /* ÇIKTISI:
["Merhaba ", "sana ", "ey ", "Merhaba ", "sana "]
*/

Burada bir diğer husus, aynı şeyleri referans türü olan class ile değil de struct ile yaparsanız farklı sonuçlar alırsınız. Çünkü taa başta, kelimeler oluşturulurken tek nesne var ve kopyaları alınmıyor. O yüzden bir satırda kelime sonuna boşluk eklenirken, diğer satırda aynı nesneye işaret eden başka bir liste kurabiliyor (push satırı) ve kelimeler dizisi dahil her yerde aynı veri işaret ediliyor. Eee tabi aynı sonucu şöyle de elde edebilirdik:

  kelimeler.cycle.take(5).writeln;
  // [Merhaba , sana , ey , Merhaba , sana ]

Ancak bağlı listeler ile de çalışmak güzel çünkü aynı yapıya link'leri bölen veya çıkaran başka işlevler yazabilir ya da bölünen/çıkarılan yere başka listelerin düğümlerini ekleyebilir ya da birden fazla roots[] ile listenin istediğiniz yerine çapa (anchor) atabilirsiniz.

Sıralama algoritmaları dahil birçok ikili listelerde kullanılan bu teknikler, yerine göre dizilerden daha hızlı sonuç verebilmektedir.

Başarılar...

February 20, 2023
On 2/19/23 15:56, Salih Dincer wrote:

> struct CircularList(Node) // v1.1 for D Class
> {

[...]

>    /********************** Input Range Functions */
>    enum empty = false;
>    auto front() { return items.link.CLL; }
>    void popFront() { items = items.link; }
>    /*                (InputRange)                */
> }

Burada beni rahatsız eden şey, topluluk kavramıyla aralık kavramının birbirine karışmış olması.

Gösterdiğin forum konusundaki LinkedListAdapter ise yalnızca aralık işlevleri işini çözmeye çalışmış. Mantıklı da: Kullanıcının bağlı liste türü varsa, push() gibi işlevleri de vardır diye düşünülebilir.

Öte yandan, belki de sen push() gibi işlemleri de halletmek istiyorsun. O zaman bütün işi neden sen yapmayasın? Yani, kullanım amacı biraz dar gibi geliyor.

O zaman struct/class sorunu da ortadan kalkar.

Ek olarak, bir veri yapısının kendi düzeneğinin ekleme, vs. işlemlerinin class düzeneği ile değiştirilebiliyor olması bana gerekliymiş gibi gelmiyor. Bunu yalnızca bu güne kadar görmediklerime :) dayanarak söylüyorum. Sonuçta, bağlı liste düğümünün class olmasını gerektiren bir durum düşünemiyorum.

> Kodu, static if'ler (sadece class ve struct) ile kısıtladığımızda,
> derleyici önce alias'ların token'nını çözdüğü için şu test assert'e
> uğramıyor:

Aklıma senin de düşünmüş olduğun iki seçenekten başkası gelmiyor:

struct CircularList(Node) // v1.2 for D
if (is (Node == struct) ||
    is (Node == class))
{
  // ...
}

Öyle yapınca derleyici okunaklı mesaj veriyor:

Error: template instance `deneme.CircularList!(Test)` does not match template declaration `CircularList(Node)`
  with `Node = Test`
  must satisfy one of the following constraints:
`       is(Node == struct)
       is(Node == class)`

(Ama satırları doğru hizalayamamışlar. :/ Acaba sen mi düzeltsen? ;) )

İkinci seçenek de tabii  bir 'static if' daha kullanmak olabilir.

Ali

February 27, 2023

On Monday, 20 February 2023 at 17:16:24 UTC, Ali Çehreli wrote:

>

Burada beni rahatsız eden şey, topluluk kavramıyla aralık kavramının birbirine karışmış olması.

Bir cevap vermeden evvel, kitaptan okuma yapıp bilgileri tazeleyelim. Yine de her şey basit çünkü programlamada bana göre 2 tanım vardır: Algoritma ve Bilgi (kısaca AI) ve gerisi bunlar üzerine inşaa edilmiş şeyler bütünü ama bu sayfadaki tanımlar çok güzel, nakletmeliyim...

Haydi, adım adım gidelim:

>

Daha ileri gitmeden önce aralıklarla doğrudan ilgili olan topluluk ve algoritma tanımlarını hatırlatmak istiyorum.

Topluluk (veri yapısı):
Topluluk, neredeyse bütün programlarda karşılaşılan çok yararlı bir kavramdır. Değişkenler belirli amaçlarla bir araya getirilirler ve sonradan bir topluluğun elemanları olarak kullanılırlar. D'deki topluluklar; diziler, eşleme tabloları, ve std.container modülünde tanımlanmış olan topluluk türleridir. Her topluluk belirli bir veri yapısı olarak gerçekleştirilir. Örneğin eşleme tabloları bir hash table veri yapısı gerçekleştirmesidir.

Her veri yapısı türü, elemanları o veri yapısına özel biçimde barındırır ve elemanlara o veri yapısına özel biçimde eriştirir. Örneğin dizi veri yapısında elemanlar yan yana dururlar ve sıra numarası ile erişilirler; bağlı liste yapısında elemanlar düğümlerde saklanırlar ve bu düğümler aracılığıyla erişilirler; ikili ağaç veri yapısında düğümler kendilerinden sıralamada önceki ve sonraki elemanlara farklı dallar yoluyla erişim sağlarlar; vs.

Ben bu bölümde topluluk ve veri yapısı deyimlerini aynı anlamda kullanacağım.

Devamı...

Yazdıklarını birkaç kere okudukça daha iyi anlıyorum ama dizilerin de bir topluluk olduğunu ve D aralık gibi kullanıldığını düşününce belki de anlayamıyorum, anlamamışımdır 😀

Üstelik yukardaki gibi, alt başlığın 2. paragrafında, bağlı liste ve düğüm gibi konular işlenince bu tanımları ayırmanın (en azından D için) anlamı olmadığını söyleyebiliriz. Belki Node(düğüm) temelindeki kafa karışıklığına işaret ediyorsun?

Oysa ben karmaşıklığı basitleştirmeyi ve tıpkı bir lokomotif kuyruğuna bağlı vagonların raylarda ilerlemesi (as a rail-car: insert front) ile bir petrol istasyonundaki sondanın ucuna eklendikçe (as an oil-rig: insert back) derinlere inmenin bezerliğini (aslında FIFO, bu başlıktaki uygulama) ortak paydada bir araya getirmeyi amaçladım.

Topluluklarda alıştığımız şöyle değil midir?

Herhangi bir temel türün yanına, [] işaretlerini getirdiğimizde onun artık bir değişken(birey) olmadığı dizi(topluluk) olması için her yeni üye (eleman) eklemeyi ~= işleçi ile yapmamız gibi. Pekala push()'u arka plana itip şu 2 işlev ile D dostu hale getirebiliriz:

  void opOpAssign(string op : "~")(Type value) {
    push(value);
  }

  void opOpAssign(string op : "~")(Type[] values) {
    foreach(value; values) push(value);
  }

Acaba seni rahatsız eden şu mu?

Aşağıda, 2. çıktıda göstermeye çalıştığım gibi Köpek sınıfının kendiniKoru() özelliğini kaybediyor çünkü aralığın dönüş türü bir dizge (string) ve pekala struct Node { ... } şelinde ayrı olarak tanımlanabilir.

Evet, makul görünüyor...

import std.range;
import std.stdio;

alias MyList = DairesellBağlıListe;

void main()
{
  auto hektor = new Pitbull(" ısırırım");
  auto terier = new Köpek(" hem de ısıran Terrier");

  foreach(köpek; [hektor, terier])
  {
    köpek.write(" hayvanıyım ben,");
    köpek.kendiniKoru.writeln;
  } /* ÇIKTISI:
    Pitbull hayvanıyım ben, havlarım ve kaçamazsan ısırırım
    Köpek hayvanıyım ben, hem de ısıran Terrier
  */

  MyList!Köpek köpekler;
  köpekler ~= ["Pitbull", "Terrier", "Bulldog"];

  foreach(köpek; köpekler.take(6))
  {
    köpek.write(", ");
    // köpek.kendiniKoru.writeln; // çalışmaz!
  } /* ÇIKTISI:
    Pitbull, Terrier, Bulldog, Pitbull, Terrier, Bulldog
  */
}

/*
Bu arada yukardaki örnek kodun derlenebilmesi için 2 örnek sınıf ve CircularList'in yeni sürümüne ihtiyacınız olacak:
*/

struct SınıflarlaDairesellBağlıListe(Düğüm)
{ // v1.3 for D
  private Düğüm items;
  private Düğüm root;

  size_t length; // <-- TotalSize'a dahil edilmeyecek!
  enum Size = size_t.sizeof;

  alias T = Düğüm.ANA;
  alias Type = typeof(T);

  // Bu yapının operasyonel bellek maliyetini yazdırma:
  string toString() const {
    import std.format: format;
    return format("%s!%s(%s[%s] %s):  %s bytes"
           , __traits(identifier, typeof(this))
           , __traits(identifier, Düğüm)
           , Type.stringof
           , this.length
           , __traits(identifier, T)
           , __traits(getPointerBitmap, this)
           [0] - Size + length * Size);
  } //      ^-- TotalSize, byte cinsinden!

  // ~= ile tek eleman ekleme:
  void opOpAssign(string op : "~")(Type value) {
    push(value);
  }

  // ~= ile birden fazla eleman ekleme:
  void opOpAssign(string op : "~")(Type[] values) {
    foreach(value; values) push(value);
  }

  void push(Type value) {
    if(isEmpty) {
      items = new Düğüm(value, null);
      root = items;
    } else {
      items.link = new Düğüm(value, root);
      popFront();
    }
    ++length;
  }

  // Listenin boş(null) işaret ettiği elamanı mı?
  auto isEmpty() { return !items; }

  // Temel InputRange İşlevleri:
  enum empty = false;
  auto front() { return items.link.ANA; }
  void popFront() { items = items.link; }
}

class Köpek
{
  string tekmelenirsem;
  alias ANA = tekmelenirsem;
  Köpek link;

  this(string varsayılanDavranış, Köpek link = null) {
    tekmelenirsem = varsayılanDavranış;
    this.link = link;
  }

  string kendiniKoru() {
    return tekmelenirsem;
  }

  override string toString() {
    return __traits(identifier, typeof(this));
  }
}

class Pitbull : Köpek
{
  string tekmelenirsem;

  this(string varsayılanDavranış)
  {
    this.tekmelenirsem = varsayılanDavranış;
    super(" havlarım");
  }

  override string kendiniKoru() {
    return super.tekmelenirsem ~ " ve kaçamazsan"
           ~ this.tekmelenirsem;
  }

  override string toString() {
    return __traits(identifier, typeof(this));
  }
}

Saygılar, sevgiler Salih Dinçer...

February 27, 2023
On Monday, 20 February 2023 at 17:16:24 UTC, Ali Çehreli wrote:
> Ek olarak, bir veri yapısının kendi düzeneğinin ekleme, vs. işlemlerinin class düzeneği ile değiştirilebiliyor olması bana gerekliymiş gibi gelmiyor. Bunu yalnızca bu güne kadar görmediklerime :) dayanarak söylüyorum. Sonuçta, bağlı liste düğümünün class olmasını gerektiren bir durum düşünemiyorum.

Ben de düşünemiyordum, ta ki sınıfların üstünlükleri zihnimde belirmeye başlayıcaya kadar! Hatta yakın vir zamana kadar her şeyin struct'lar ile yapılabildiğini class'lara da ne gerek var canım diye geleneksel tarafı savunurdum :)

Bakın, bir de geçen hafta şöyle demişim:

> On 2/19/23 15:56, Salih Dincer wrote:
> 
> Burada bir diğer husus, aynı şeyleri referans türü olan class ile değil de struct ile yaparsanız farklı sonuçlar alırsınız. Çünkü taa başta, kelimeler oluşturulurken tek nesne var ve kopyaları alınmıyor. O yüzden bir satırda kelime sonuna boşluk eklenirken, diğer satırda aynı nesneye işaret eden başka bir liste kurabiliyor (push satırı) ve kelimeler dizisi dahil her yerde aynı veri işaret ediliyor...

Tabi belleğin operasyonel maliyetini minimize etmek için struct Node kullnmak akıllıca sanırım.

Başarılar...
February 27, 2023
[En sonda "Tamam, haklısın." diyorum.]

On 2/26/23 20:03, Salih Dincer wrote:

> dizilerin de
> bir topluluk olduğunu ve D aralık gibi kullanıldığını düşününce

Bunları bildiğini biliyorum. Başka arkadaşlar için tekrarlıyorum.

D'nin dizi (array) ve dilim (slice) kavramları, basit olmaları beklendiği halde çok karışıklığa neden oluyorlar.

D'nin söz dizimi kolaylık olsun diye dizileri aralık gibi kullandırıyor ama dizi olduğu yerde dururken aralık tükenir. Diziye bir şey olmaz.

import std.range;

void main() {
    int[] dizi;                 // (1)
    dizi.length = 10;           // (2)

    dizi.popFront();            // (3)
    assert(dizi.length == 9);   // (4) Evet, 9 ama 10'luk dizi hâlâ yaşıyor
}

1) Programda öyle değişkenlere "dizi" diyoruz ama int[]'in türü dilimdir.

2) Dinamik bellekte 10 elemanlı adsız bir dizi oluşturulur (evet, bu bir dizidir). Ve bizim değişkenimiz onun bütününe erişim sağlayacak duruma gelir.

3) Dilimin başında kısaltırız. Dilim kısalır, diziye bir şey olmaz.

4) 3'ü gösterimi.

Buradaki yanılgı şuradan kaynaklanıyor: Dinamik bellekte yaşamakta olan adsız dizinin uzunluğu hâlâ 10'dur ama elimizde tek dilim bulunduğundan biz bunu ispatlayamayız.

İspatı da basittir: başka bir dilim daha oluşturabiliriz ve o da baştaki 10 elemanı gösterir. Hâlâ tek dizi vardır ama artık iki dilim vardır.

Tabii bunlardan birisine eleman ekleyince yeni bir dinamik dizi oluşturulabilir. (Hangisine eklendiğine bağlı olarak yeni dizi oluşturulmayabilir de. Bu da büyük bir karışıklıktır.)

> Belki Node(düğüm) temelindeki kafa
> karışıklığına işaret ediyorsun?

Hayır, yalnızca her veri yapısının kendi gerçeklemesine özgü erişimleri olduğunun örneklerini vermeye çalışmışım.

Ama burada başkaca bir karışıklık daha vardır: C++ zamanlarında birisinin yaptığı bir gözlemi hatırlıyorum: Ağaç veri yapısı için farklı bir erişici (iterator) arayüzü olamayacağını çünkü ağacın zaten aynı şey olduğunu söylemişti. (Ya da buna benzer bir şeydi.)

Aynı gerçek, bağlı liste için de var: Bağlı liste topluluğunun gerçekleştirilmesiyle onun erişicisinin (yani, D'deki aralık kavramı) gerçekleştirilmesi aynı.

Sen de o yüzden front'u vs. oraya yerleştiriyorsun.

> Oysa ben karmaşıklığı basitleştirmeyi ve tıpkı bir lokomotif kuyruğuna
> bağlı vagonların raylarda ilerlemesi (as a rail-car: insert front) ile
> bir petrol istasyonundaki sondanın ucuna eklendikçe (as an oil-rig:
> insert back) derinlere inmenin bezerliğini (aslında FIFO, bu başlıktaki
> uygulama) ortak paydada bir araya getirmeyi amaçladım.

Tamam. O iki örnekte de topluluğa ekliyoruz.

> Topluluklarda alıştığımız şöyle değil midir?
>
> Herhangi bir temel türün yanına, `[]` işaretlerini getirdiğimizde onun
> artık bir değişken(birey) olmadığı dizi(topluluk) olması için her yeni
> üye (eleman) eklemeyi `~=` işleçi ile yapmamız gibi. Pekala `push()`'u
> arka plana itip şu 2 işlev ile D dostu hale getirebiliriz:
>
> ```d
>    void opOpAssign(string op : "~")(Type value) {
>      push(value);
>    }
>
>    void opOpAssign(string op : "~")(Type[] values) {
>      foreach(value; values) push(value);
>    }
> ```

Onlar da tamam. O işlemler toplulukta bulunmalı.

> Acaba seni rahatsız eden şu mu?

Tek rahatsızlığım, topluluk ile aralığın farklı türler olması gerektiğini düşünmemden kaynaklanıyordu. Ama denediğim halde senin kodunda yanlış kullanıma yol açacak bir şey bulamıyorum. Bunu, bu türdeki sonsuzluğa bağlıyorum. Tükenme diye bir şey olmadığına göre benim "topluluk tükenmemeli, aralık tükenmeli" türündeki rahatsızlığım burada yok.

Tamam, haklısın.

Ali

February 28, 2023

On Monday, 27 February 2023 at 13:33:51 UTC, Ali Çehreli wrote:

>

[En sonda "Tamam, haklısın." diyorum.]

On 2/26/23 20:03, Salih Dincer wrote:

>

dizilerin de
bir topluluk olduğunu ve D aralık gibi kullanıldığını
düşününce

Bunları bildiğini biliyorum. Başka arkadaşlar için tekrarlıyorum.

Hocam, öncelikle cevabınız için teşekkürler. Ama kimin haklı olduğundan ziyade, çok sık kullanılmayan, eskide kalan bir programlama tekniğini nasıl daha kolay kullanabiliriz, nasıl hayatımızda daha çok yer edinmesini sağlayabilirizin peşindeyim.

İşte bu yüzden, sadece işe gidiş/gelişte servis içinde yazdığım şu 4 maddeyi izninizle paylaşmak istiyorum. Yazalı 24 saat olmadı ve okuma sabrı gösterirseniz ortak noktalardan D'nin ne kadar kolay ve modern bir dil olduğu sonucuna varmaya çalışacağız.

Okuma sabrı gösterenlere de teşekkür ederim:

>

1.'si, hangi programlama dili olursa olsun, bağlı listeleri (Linked List) oluşturmak için en az 2 alandan oluşan bir düğüm(Node) topluluğuna ihtiyaç vardır. Bu en temel ortak noktadır ve istinasız, alanlardan biri başka düğümü işaret eden tür (pointer) olmasıdır. Örneğin yapı (struct) için şöyle:

struct Node {
  int data;
  Node * next; // bu bir pointer
}

Java, Python gibi nesne yönelimli dilerde ise struct yerine class kullanılır. Hali hazırda referans türü kullanıldığından işaretçi (pointer) olmadan şu şekilde yazılır:

class Node {
  int data;
  Node next, prev; // bunlar da bir pointer
}

2.'si, bir de çift yönlü düğümler/listeler olduğu için 3. bir Node * prev isminde alanı da kullanılmaktadır. İsimler, bazen value/link veya item/iter şeklinde de farklılaşabilir. Ama genelde sonraki düğüm işaret edildiği için büyük bir çoğunlukla Node * next ismi kullanılır.

3.'sü, ayrıca Circular List isminde sonsuz/tükenmeyen dairesel özellikte liste türü de vardır. Bunun dışında kalan listelerin mutlaka null (hiçbir adrese işaret etmeyen) düğümleri vardır. İşte bu sayede, baştaki ve/veya sondaki düğüm hiçbir adresi işaret etmediğini null ile karşılaştırılarak listenin ucuna geldiği anlaşılır.

4.'sü, ister topluluğun dışarda, ister başka bir yapı veya sınıf içinde olsun, ekleme/çıkarma vb. işlevler ile tüm operasyon, basit mekanizmalar ile tanımlanabilir. Bazen de Node tolululuğu, başka bir topluluk içinde kapsüllenmiş de olabilir.

Bu 4. maddeden sonra ortak noktalar gittikçe azalıyor. Örneğin D programlama dilinde aralıklar (range) kullanılarak pratik sonuçları olan mekanizmalar/algoritmalar geliştirilmesi mümkündür.

Üstelik D'de, diğer birçok dilde olduğu gibi bir işaretçi (pointer) mücadelesi yoktur. Sadece bir nokta ile bir nesne içine erişilebilir.

Aslında bir ara Multi-Threading LinkedList başlığında konuyu daha da teknik boyuta taşımız. Özetle D'yi seviyorum, özellikle de işin içine class girdiğinde ne bir yıldız (işaretçi işleçi: *) ne de parantezler (işaretçinin nesneye dönüşmesi) olmadan basitçe noktalar kullanılmasını.

Bilmiyorum dikkatleri çekti mi? Bu son örnekte, tek bir yıldız ve fazladan kullanılan parantezler yok. Aslında faha çok mevzu var da yavaş yavaş 😀

Sevgiler, saygılar...

February 28, 2023

On Sunday, 19 February 2023 at 23:56:21 UTC, Salih Dincer wrote:

>

Kodu, static if'ler (sadece class ve struct) ile kısıtladığımızda, derleyici önce alias'ların token'nını çözdüğü için şu test assert'e uğramıyor:

void main() {
  enum Test { none }
  CircularList!Test itsnotacontainer;
}

Ama bu testi başarıyla, yani hata mesajıyla geçiyor:

void main() {
  enum Test { CLL }
  CircularList!Test itsnotacontainer;
}

Sonunda bir çözüm buldum, üstelik static assert'den de kurtuldum. Çözümü şurada basit bir örnekle yayınladım. Aslında yaptığım sadece kodu bir mixin template ile parçalamaktı. Derleyici, mixin'lere biraz daha yumuşak davranıyor 😀

Düşünsenize, teorik olarak yine aynı kod oluşuyor ama derleyici bulamadığı bir şey olsa bile şablondan geldiğini varsayıyor ve/veya o gelenleri çok kurcalamıyor. Özetle şablonlara özel insan (VIP) muamelesi görüyoruz!

Sevgiler, saygılar...