September 04, 2022

On Tuesday, 23 October 2012 at 23:29:19 UTC, Ali Çehreli (acehreli) wrote:

> >

On Tuesday, 23 October 2012 at 21:38:02 UTC, Ali Çehreli (acehreli) wrote:

>

D'de bu konuyu da ilgilendiren bir gariplik var: foreach'in bazı kullanımları aslında 'static foreach'. Ama D'de açıkça 'static foreach' diye yazılan bir şey yok.

Örneğin, aşağıdaki koddaki foreach çalışma zamanında işletilmiyor, derleme zamanında işletiliyor:

import std.stdio, std.traits;
void main() {
   enum Günler { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar }

   foreach (gün; EnumMembers!Günler) {
       writeln(gün);
   }
}

Sanırım bu çok normal çünkü bu bir şablon. İçeriğinde mixin'ler falan olmalı...

Cahilce bu durumu ilerleteceğim; işin içine enum giriyorsa eğer, static bir şeyler olduğunu düşünüyorum. Yani key/value olarak değerlendirirsek value kısmında hiç bir sorun yok. Ama key'leri de kullanıyorsak, elemanların isimleri static veri olarak yerleştiriliyor. Bunu assembly kodlarında görmüştüm. Ancak bu veri, çağrılabilen cinsten yani bir yerde string olarak duruyor ve o adres hafızaya alınıp ilgili işleve dallanılıyor.
Orası tamam. Ama foreach kendisi şablon veya mixin değil.

Buradaki gariplik, EnumMembers!Günler'in ürettiği ile kullanıldığında ortada foreach'in kalmıyor olması. Onun yerine yedi tane işlem geliyor.

Yani şu iki döngü birbirinden çok farklı:

   // Yedi adet writeln() satırı
   foreach (gün; EnumMembers!Günler) {
       writeln(gün);
   }

   // Çalışma zamanında yedi kere işletilen bir döngü
   foreach (gün; [ EnumMembers!Günler ]) {
       writeln(gün);
   }

Ali hocanın neredeyse 10 sene önce verdiği bu dersi unutmuşum! EnumMembers'ı unutmamıştım (zaten başımız sıkıştıkça kullanırız!) ama dizi içine yerleştirip derleme zamanında eleman üretmesini sağlama hatrımdan çıkmış. Başlığı tekrar hortlatma pahasına devam edelim mi?

Aslında başka bir başlık açmak isteyen buraya bir referans vererek devam edelibilir. Çünkü 3 sayfanın tamamı sağlam bir ders konusu: Enum'lar ve Üyeleri

Tabi aradan geçen zaman zarfında (cycle() o zamanlar var mıydı?) çok şey değişmiş olabilir. Yoksa buradaki konuştuklarımız (tabi yine aynı olanağı kullanarak) tek satır gibi bir şey:

void main()
{
  import std.range : cycle, take;
  import std.traits : EnumMembers;

  enum test { a, b, c }
  cycle([EnumMembers!test]).take(4).writefln!"%-(%s%)"; // abca
}

Bir de bunun eşdeğeri var benim kullandığım, kütüphanemde sakladığım; dursun burda da:

struct InfinityEnum(alias E)
{
  import std.traits : EnumMembers;
  const E[] member = [EnumMembers!E];
  private size_t i;

  enum empty = false;
  auto front() const { return member[i]; }
  void popFront() { if(++i == member.length) i = 0; }
}

unittest
{
  enum test { a, b, c }
  test[] abca;
  with(test) abca = [a, b, c, a];

  InfinityEnum!test foo;

  import std.range : take;
  auto range = foo.take(4);

  import std.algorithm.comparison : equal;
  assert(equal(range, abca));
}

Avantajı, aralık görünümlü diziyi ekstra cycle() algoritmasından geçirmeyip doğrudan take() ile kullanabilmek ve ekstra EnumMembers'ı import etmeyip hızlıca çağırmak. Neyse tarih tekerrürden ibarettir; mazur görün beni, başlığı hortlattığım için. Rabbim bir 10 sene daha yaşatırsa bizi, 50'li yaşlarımızda yine gelir buralara değiniriz inşaallah bu konulara...:)

Dip Not: Ayrıca önceki sayfanın sonundaki iletide, EnumMembers şablonunun bir örneğini nakletmişim!

Hoşça kalın.

September 04, 2022
On 9/4/22 01:36, Salih Dincer wrote:

> EnumMembers'ı unutmamıştım (zaten başımız sıkıştıkça kullanırız!) ama
> dizi içine yerleştirip derleme zamanında eleman üretmesini sağlama
> hatrımdan çıkmış.

Orada "çalışma zamanı" daha doğru galiba: [ EnumMembers!E ] yazınca dizi normalde çalışma zamanında üretilir. Ama 'static const' denirse derleme zamanında üretilir. (Başka türlerde 'static const'ın yerine, burada biraz daha farklı anlama gelen 'enum' da kullanılabilir ama o enum'ın dizilerde masrafı vardır.)

Ama sen [EnumMembers!E]'yi yalnızca InfinityEnum.member'ın ilk değeri olarak kullandığından 'static const'tan önemli bir farkı yok:

>    const E[] member = [EnumMembers!E];

Olsa olsa nesne büyüklüğünden söz edebiliriz. Şöyle yapsak:

struct InfinityEnum_2(alias E)
{
   static const E[] member = [EnumMembers!E];
   // ...
}

enum E { a, b, c }

pragma(msg, InfinityEnum!E.sizeof);    // 24
pragma(msg, InfinityEnum_2!E.sizeof);  //  8

Evet, 'static const' daha küçük oluyor ama hiçbir programda bir sürü InfinityEnum nesnesi kullanılacağını düşünemeyiz herhalde. :) Yani, pek önemli değil ama akılda bulunsun.

Ali

1 2 3 4
Next ›   Last »