Thread overview
struct'lar ile ilgili (işin içinden çıkamadım!)
Feb 05, 2023
Salih Dincer
Feb 05, 2023
Ali Çehreli
Feb 05, 2023
Salih Dincer
Feb 05, 2023
Salih Dincer
Feb 05, 2023
Ali Çehreli
Feb 05, 2023
Ali Çehreli
Feb 07, 2023
Salih Dincer
Feb 07, 2023
Ali Çehreli
Feb 07, 2023
Ali Çehreli
Feb 08, 2023
Salih Dincer
February 05, 2023

Merhaba,

İlk olarak aşağıdaki gibi bir yapımız olsun; tür şablonu ile çevrelenen:

struct Enumlarım(T)/*
alias T = int;
struct Enumlarım//*/
{
  enum UzunAdıOlanTürüm : T
  {
    False, True
  }
  //...
}

Yani buradaki şablon parametresi olan T'ye dikkat. Aslında Enumlarım yapısını bir instance name ile ilişkilendirmek istemiyorum ama aşağıdaki gibi kurmak zorunda kalıyorum çünkü o zaman Bool alias'ı kurulmuyor!

void main()
{
  // Kurulum:
  Enumlarım!int enumlarım;
  alias Bool = enumlarım.UzunAdıOlanTürüm;

  // Kontrol:
  auto selamVer(Bool vereyim_mi) {
    return vereyim_mi ? "selam" : "küstüm :)";
  }

  // Sonuç:
  import std.stdio;
  Bool selam;
  selamVer(++selam).writeln; // selam
}

Eğer Bool ='den sonra büyük harfle (lütfen değiştirip deneyin) doğrudan takma ad oluşturursanız çok garip bir hata alıyorum:

>

source_file.d(16): Error
identifier UzunAdıOlanTürüm of Enumlarım.UzunAdıOlanTürüm is not defined

Neden böyle? Aslında cevabını biliyorum, sanırım! Eğer örnek kodun en üstünü kaparsanız (// - toggle comment ekleyin) T'yi yapıdan ayırmış olacaksınız. Eee tabi enumlarım'ı artık silin gitsin ve şu şekilde çalıştığını göreceksiniz:

alias Bool = Enumlarım.UzunAdıOlanTürüm;
auto selamVer(Bool vereyim_mi) {
  return vereyim_mi ? "selam" : "küstüm :)";
}

import std.stdio;
void main()
{
  Bool selam;
  selam.selamVer.writeln; // küstüm :)
}

struct Enumlarım {
  enum UzunAdıOlanTürüm { False, True }
}

Özetle, cevabını bildiğim bir soru çünkü şablon parametresi aldığı için o artık başka bir yapı ama alias içinde bağlayamamak üzücü. Çünkü kullandığım enum'ları bir struct içinde ve varsayılan temel veri türlerini (T) derleme anında değiştirebileceğim bir düzene ihtiyaç duyuyorum.

Diğer soru(n) az sonra...

February 05, 2023
On 2/5/23 06:45, Salih Dincer wrote:

> çünkü şablon parametresi aldığı için o artık başka bir yapı

Doğrusu, o başka bir yapı değil, bir *yapı şablonu*. Ancak (belki de otomatik olarak) T belirtildiğinde T'nin değerine göre bambaşka yenetekleri olan, bambaşka biçimde derlenen bir tür olur.

> ama alias içinde bağlayamamak üzücü. Çünkü
> kullandığım enum'ları bir struct içinde ve varsayılan temel veri
> türlerini (T) derleme anında değiştirebileceğim bir düzene ihtiyaç
> duyuyorum.

O düzenek şablonlar değil mi?

> Eğer Bool ='den sonra büyük harfle (lütfen değiştirip deneyin) doğrudan takma ad oluşturursanız

Yani, şöyle yapınca çalışmıyor:

  alias Bool = Enumlarım.UzunAdıOlanTürüm;

Çünkü UzunAdıOlanTürüm'ün ne olduğu, Enumlarım'ın T'sine bağlı olacak ama bilinmiyor. (Bazı durumlarda UzunAdıOlanTürüm 'static if' marifetiyle yok edilmiş bile olabilir.)

D'de şablonlu alias'lar kullanılabiliyor. Belki duruma göre ondan yararlanılabilir:

  alias Bool(T) = Enumlarım!T.UzunAdıOlanTürüm;

Ama eninde sonunda T'nin ne olduğunun ya açıkça programcı tarafından ya da otomatik olarak kullanımdan anlaşılması gerekiyor.

Ali

February 05, 2023

On Sunday, 5 February 2023 at 14:45:46 UTC, Salih Dincer wrote:

>

Diğer soru(n) az sonra...

Aslında çok sorum var ve bunları İngilizce forumda sormak istemiyorum çünkü anlamıyorlar. Sanırım benim engin İngilizce dilim onlara çok geliyor! Oxford'da okumak başka tabi... 😀

Şaka bir yana hakikaten İngilizce yazmak zor bea. Teknik terimleri bilmeyince anlamıyorlar da. Translator da anlamıyor/çeviremiyo 😞

Bir yardım lütfen ve gelelim asıl soruya...

Aşağıdaki gibi çalışan kodumuzun, #line 1 ile işaretlenen bölümde nasıl oluyorda kurucuya paremetre göndermeden kurulabilir?

import std.stdio;

void main()
{
  auto num = [68, 76, 65, 78, 71];
  auto str = "abcd12345";
  auto funy = Funy!long(str);
  funy.writeln(": ", funy.length);

  Funy!long foo;
  foo.writeln;

  foo = funy; // belli ki burada kopyalanmadı:
  funy.ws[1] = funy.ws[1].init;
  foo.writeln;

#line 1
  auto bar = Funy!long(); /*
  auto bar = Funy();//* Error: */
  // source_file.d(2): none of the overloads of struct `source.Funy` are callable using argument types `!()()`
  // source_file.d(7): Candidate is source.Funy(alias T = size_t)
}

template Funy(alias T = size_t) {
  struct Funy {
    Word[] ws;
    struct Word {
      T[T.sizeof] letters;
      auto toString() {
        return cast(string)letters;
      }
    }
    //@disable this(this);
    this(A)(A[] arr) {
      size_t size, cell;
      foreach(data; arr) {
        if(cell == T.sizeof) {
          cell = 0;
          size++;
        }
        if(cell == 0) {
          ws ~= Word(0);
        }
        ws[size].letters[cell++] = cast(T)data;
      }
    }
    size_t length() {
      return ws.length;
    }
  }
}

Hadi onun bir özellik olduğunu düşünelim, şablon paremetresi olmadan şöyle varsayılan türü belirttiğimde:

template Funy(alias T = size_t) {
 //...

Neden bir helper() kolaylık işlevi yazmadan tür belirtme şartı koşulur? Çünkü ilgili satırı açınca 2 ve 7. satır hatalarını alıyorum.

Aslında foo'ya funy'i kopyaladığımı zannettikten sonra funy'de yapılan bir değişiklik nasıl oluyor da foo'yu etkiliyor?

Teşekkürler...

February 05, 2023
On 2/5/23 08:08, Salih Dincer wrote:

> çünkü anlamıyorlar.

Doğrudur. Ama olabildiğince ilgi çekmek de önemli. Ben senin kodlarında hep zorlanmışımdır. En önemlisi, kodlarda asıl soruyla ilgisi olmayan şeyler de bulunuyor. Ve koda bakan kişi konu onlarla ilgiliymiş gibi düşünebiliyor ve bakıyor, bakıyor, vs. Bazen 'alias this' ve 'with' gibi iyice zorlaştıran şeyler bile giriyor.

Sordun diye söyledim. :) Az ve öz olmalı.

> Aşağıdaki gibi çalışan kodumuzun, #line 1 ile işaretlenen bölümde nasıl
> oluyorda kurucuya paremetre göndermeden kurulabilir?

Belki de bu konuyu zaten bildiğim için buradaki kodun şöyle de yazılabileceğini de biliyorum. Ama sen de çıkartabildiğin kadar kod çıkartıp olabildiğince kısaltabilirsin:

struct S(T = int) {}

void main() {
    // auto a = S();   // Derlenemez
    auto b = S!()();  // Derlenir
}

Tür şablonları, bütün şablon parametrelerinin varsayılan değerleri olsa bile şablon parametre listesinin yazılmasını gerektirirler. Evet, garip... Ama sanırım geçerli bir nedeni var: S, her zaman için şablonun adıdır. Dolayısıyla, S() yazmak yetseydi, şablonu işlev gibi kullanıyoruz gibi olurdu... Herhalde... Emin değilim.

Bu gibi durumlarda ben alias veya işlev kullanıyorum:

alias VarsayılanS = S!();

    auto a = VarsayılanS();   // Şimdi derlenir

İşlevle:

auto varsayılanS() {
    return S!()();
}

    auto c = varsayılanS;    // Bu da derlenir

Bu konuya değinmişim:


http://ddili.org/ders/d/sablonlar.html#ix_sablonlar.varsay%C4%B1lan%20%C5%9Fablon%20parametresi

Hiç önemsiz olarak ve doğru anlıyorsam, bir 'n' daha olmalı: Funny.

Ali

February 05, 2023
On 2/5/23 08:08, Salih Dincer wrote:

> Aslında foo'ya funy'i kopyaladığımı zannettikten sonra funy'de yapılan
> bir değişiklik nasıl oluyor da foo'yu etkiliyor?

import std.stdio;

struct S {
    int[] dizi;
}

void main() {
    auto a = S([ 42 ]);
    auto b = a;
    a.dizi[0] = 43;
    assert(b.dizi[0] == 43);   // Aynı diziyi paylaşıyorlar
}

C'de de olduğu gibi, varsayılan kopyalama işlemi "shallow"dur. Yani dizileri ve hatta onların elemanlarını vs. kopyalamaz. Çünkü belki de üyenin paylaşılması istenmektedir; derleyici bu kararı veremez. Ve masrafsız olan yöntem seçilmiştir.

Gereken durumlarda opAssign, this(this), veya kopyalayıcı yazılabilir.

Ali

February 05, 2023

On Sunday, 5 February 2023 at 15:43:19 UTC, Ali Çehreli wrote:

>

D'de şablonlu alias'lar kullanılabiliyor. Belki duruma göre ondan yararlanılabilir:

alias Bool(T) = Enumlarım!T.UzunAdıOlanTürüm;

Ama eninde sonunda T'nin ne olduğunun ya açıkça programcı tarafından ya da otomatik olarak kullanımdan anlaşılması gerekiyor.

Çok teşekkür ederim hocam, alias'ın bu özelliğini bilmiyordum. Şablon kısmında elim inanılmaz güçlendi. Gerçi enum'larımı bir yapıda toplama macerasına aşırı bir kartkısı olmadı ama o soru şekerlemeydi. Asıl konuyu Voldemort ile çözdüm:

void main()
{
  template Arr(alias T = size_t) {
    struct Word {
      T[T.sizeof] letters;
      auto toString() { return cast(string)letters; }
    }
    struct Result {
      Word[] ws;
      size_t length() { return ws.length; }
    }
    Result Arr(A)(A[] arr) {
      Result result;
      size_t size, cell;
      foreach(data; arr) {
        if(cell == T.sizeof) {
          cell = 0;
          size++;
        }
        if(cell == 0) {
          result.ws ~= Word(0);
        }
        result.ws[size].letters[cell++] = cast(T)data;
      }
      return result;
    }
  }
  import std.stdio : writeln;
  auto foo = Arr("deneme123");
  foo.writeln(": ", foo.length);
  // Result([deneme12, 3]): 2
}

Başka mevzular da var, çok meşgul etmek istemiyorum. Çözcem! 😉

Sevgiler, saygılar...

February 07, 2023

On Sunday, 5 February 2023 at 17:28:02 UTC, Ali Çehreli wrote:

>

C'de de olduğu gibi, varsayılan kopyalama işlemi "shallow"dur. Yani dizileri ve hatta onların elemanlarını vs. kopyalamaz.

Bu durum statik diziler için geçerli değilmiş. Örneğin şurada kopyalayıcı devre dışı (@disable) da değil kişiselleştirilme yapılmamış da:

void main()
{
    auto far = Sarr!()("DLANG'99".dup);
    auto bar = far;

    far[ 0 ] = 'C';
    assert(far[0] != bar[ 0 ]);

    auto hash = cast(size_t)far;
    assert(hash == 4123370121043463235);

    hash++; // ilk harfteki fark sadece 1
    assert(hash == cast(size_t)bar);
}

template Sarr(alias T = char)
{
    enum s = size_t.sizeof / T.sizeof;
    struct Sarr
    {
        union
        {
            size_t e;            
            T[s] arr;
        }
        static length = s;
        /*
        this(this)
        {
            arr = arr.dup;
        }//*/

        this(A)(A[] arr) in(s >= arr.length)
        {
            foreach(i, e; arr)
            {
                this.arr[ i ] = cast(T)e;
            }
        }

        auto toString() { return cast(string)arr; }
        auto opCast(CastT : size_t)() { return e; }
        auto opIndex(size_t i) { return arr[ i ]; }
        auto opIndexAssign(T a, size_t i) in(i < s)
        {
            return arr[ i ] = a;
        }
    }

Başarılar, sizi bilmem ama benim çok ihtiyacım var...

February 07, 2023
On 2/7/23 15:25, Salih Dincer wrote:
> On Sunday, 5 February 2023 at 17:28:02 UTC, Ali Çehreli wrote:
>>
>> C'de de olduğu gibi, varsayılan kopyalama işlemi "shallow"dur. Yani
>> dizileri ve hatta onların elemanlarını vs. kopyalamaz.
>
> Bu durum statik diziler için geçerli değilmiş.

Tam doğru söylemek gerekirse statik diziler için de öyledir: Onlar da "shallow" kopyalanırlar. Gözlemlenen fark, statik dizilerin değer türü olmalarından geliyor. Zaten "shallow" kopyalama demek, değerleri kopyalamak ama göstergeleri izlememek demektir.

Aslında dinamik diziler de değer olarak kopyalanırlar ama onlar aşağıdaki yapının eşdeğeri olduklarından gösterdikleri elemanlar paylaşılmış olur:

struct DinamikDizininEşdeğeri {
  size_t length;
  void * ptr;
}

Örneğin, dinamik dizilerin 'length' değerleri de kopyalanır 'ptr' değerleri de...

Kafa karıştırabilecek bir şey, dinamik diziye eleman eklemek .length'ini değiştirir; .ptr değeri ise değişebilir de, değişmeyebilir de...

Ali

February 07, 2023
On 2/7/23 15:48, Ali Çehreli wrote:

> Tam doğru söylemek gerekirse statik diziler için de öyledir: Onlar da
> "shallow" kopyalanırlar. Gözlemlenen fark, statik dizilerin değer türü
> olmalarından geliyor.

Bir sonraki buluşmamızda "D'nin dizileri" konusunu oturtalım mı? Bana önümüzdeki Pazar bile uygun.

Ali

February 08, 2023

On Tuesday, 7 February 2023 at 23:54:44 UTC, Ali Çehreli wrote:

>

On 2/7/23 15:48, Ali Çehreli wrote:

>

Tam doğru söylemek gerekirse statik diziler için de öyledir:
Onlar da
"shallow" kopyalanırlar. Gözlemlenen fark, statik dizilerin
değer türü
olmalarından geliyor.

Bir sonraki buluşmamızda "D'nin dizileri" konusunu oturtalım mı? Bana önümüzdeki Pazar bile uygun.

Ali

İyi olur hocam, örneğin bugün şu kodu yanlış okudum:

    auto arr = [ 0, 1 ];
    arr ~= ++arr[ $ - 1 ];

Nedense son elemanın bir fazlasını ekle diye okudum ve 8 kere tekrarlarsa tüm rakamların dizi içinde oluşacağını zannettim. Aslında öğrenciler için tam test sorusu:

void main()
{
    auto arr = [ 0, 1 ];
    while( arr[ $ - 1 ] < 9 ) {
        arr ~= ++arr[ $ - 1 ];
    }
    assert(arr == [0, 2, 3, 4, 5, 6, 7, 8, 9, 9]);

Cevap ise basit, tekli işleç yerine (opUnary ++), çiftli olanı (opBinary + 1) tercih edilmeli yoksa yukarda kanıtlandığı gibi yanlış sonuç çıkıyor 😀

Kolay gelsin...