October 23, 2012

Alıntı (acehreli):

>

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:

>         :        :        :
>     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.

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

Alıntı (Salih Dinçer):

>

Alıntı (acehreli:1349891236):

>

Bu yöntemden ve EnumMembers'dan yararlanınca daha da kolay...

> > enum Günler { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar }
> > auto çokuz = EnumMembers!Günler;
> > ```

> >
> Bu da iyimiş ama şu çokuzlara henüz alışamadım. Sıra onlarda galiba...:)
>

İkinci satırı ben yazmamışım. ;) Ayrıca tuple'a karşılık galiba "çokuzlu" diyoruz. (Çokuz da güzel olurmuş aslında.)

Alıntı:
> Bu bir şablon zannedersem?

Ünlem işaretine bakılırsa öyle:

 http://dlang.org/phobos/std_traits.html#EnumMembers

Bir "static çokuzlu" döndürüyormuş. Dizi içine yazınca dilim üretmesini ben de çok yeni öğrenmiştim.

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;
import 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);
}
}


Yukarıdaki kod aşağıdakinin eşdeğeri olarak derleniyor:

import std.stdio;
import std.traits;

void main()
{
enum Günler { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar }

with (Günler) {
writeln(Pazartesi);
writeln(Salı);
writeln(Çarşamba);
writeln(Perşembe);
writeln(Cuma);
writeln(Cumartesi);
writeln(Pazar);
}
}


Tabii writeln'dan başka kod olsaydı onlar da derlenmiş kodun içinde birden fazla kere bulunacaklardı. Akılda tutmakta yarar var. :)

Ali

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

Haklısın, Ali hocam...

Ama bu verdiğin örnek işlev şablonu. Benim henüz kavrayamadığım şey ise ''template' 'falanca() {' //... '}'' olayı. Adamlar static if, alias ve biraz da dilim kullanarak şahaneler yapmışlar:

https://github.com/D-Programming-Language/phobos/blob/master/std/traits.d

Şimdi baktım da evet, orada 'mixin()' kullanılmış; ama yeni bir şablon oluşturmak için...:)

Benim tek yapabildiğim ise işlev şablonu ile türü işleve bildirmek. Geçen hafta ders arasında Müzik Yapalım (http://ddili.org/forum/thread/1004) başlığında yazdığım bir iki işlev vardı. Bunu EnumMembers şablonuna uyarladığımızda aşağıdaki gibi bir şey çıktı. Bunun tek eksiği enum'un üyeleri ardışık gitmeli. Yoksa değerleri arasında boşluk olursa onları da döndüreceği için işler karışıyor. Gerçi küçük bir koşul ile süzmek (filter) olası. Bence diğer gerçek EnumMembers şablonuna göre daha dinamik ama yavaş olabilir...:)

   import std.stdio, std.range, std.format;

   enum Günler { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar }

   auto EnumMembers(T)()
   {
       string[] result;
       foreach(T x; T.min..T.max)
       {
           auto value = appender!string();
           formattedWrite(value, "%s", x);
           result ~= value.data;
       }
       return result;
   }

void main()
{
   foreach (i; EnumMembers!Günler)
   {
       writef("%s\t", i);
   }
   writef("\n");
}

Çıktısı:
'Pazartesi Salı Çarşamba Perşembe Cuma Cumartesi Pazar'

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

October 23, 2012

Alıntı (Salih Dinçer):

>

Sanırım bu çok normal çünkü bu bir şablon.

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);
   }

Alıntı:

>

İçeriğinde mixin'ler falan olmalı...

Garip olan da o: foreach mixin gibi kod üretmek için kullanılıyor. Ama bu, foreach herhangi bir şablonla kullanıldığında geçerli değil:

import std.stdio;
import std.range;

int[adet] birŞablon(int adet)()
{
   int[adet] sonuç;
   return sonuç;
}

void main()
{
   foreach (i; birŞablon!3) {
       writeln(i);
   }
}

Orada foreach bir şablonla kullanılıyor ama kod bildiğimiz sıradan bir döngü içeriyor.

Alıntı:

>

Cahilce bu durumu ilerleteceğim; işin içine enum giriyorsa eğer, static bir şeyler olduğunu düşünüyorum.

Doğru. Burada ilginç olan, EnumMembers!Günler ile [EnumMembers!Günler] kullanımları arasındaki fark. İşin güzeli, foreach'in çalışma zamanında işletilmesini istiyorsak EnumMembers!Günler'in etrafına köşeli parantezler eklemek yetiyor. (Yukarıdaki karşılaştırmada olduğu gibi.)

Alıntı:

>

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.

Mantıklı. Nasıl olsa onlar değişmez veriler. Bellekte tek yerde durabilirler.

Ali

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

March 09, 2013

Yukarıdaki kodu gruplama düzen belirteçi ile yazdığımızda meğer son elemanı yutuyormuş. Bu durumda küçük bir düzenlemeye ihtiyaç duyduğunu farkettim. Sadece işlevin içindeki 'foreach()''i geleneksel 'for()''a çevirdim:

   auto enumPrint(T)() {
       string[] result;
       for(T x = T.min; x <= T.max; x++) {
           auto value = appender!string();
           formattedWrite(value, "%s", x);
           result ~= value.data;
       }
       return result;
   }

Ama anlayamadığım bir şey de 'main()' içinde 'foreach()' ile kullandığınızda yine aynı çıktıyı almanız...

Alıntı:

>

'Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar,'

Bu biraz şaşırtıcı olsa da kafa yormak istemiyorum...:)

Çünkü şu an başka bir sorun ile boğuşuyorum. Aslında güzel bir çözüm de buldum ama geliştirmeye ihtiyaç var. Aşağıdaki kodu bir proje için yazıyorken şablon (''union'(T)') kullanmadığımı farkettim. Bu durumda özelleşmiş bir union olmuş oluyor!

import std.stdio;

enum Günler { Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, Pazar }

// rooundInc() alternatifidir:
union enumSet {
 Günler e;

 struct {
   size_t dizin;

   void opUnary(string işleç)() if(işleç == "++") {
     if(dizin < e.max) dizin++;
     else dizin = 0;
   }
 }

 string toString() const @property {
   return std.conv.to!string(e);
 }
}

void main() {
 auto test = enumSet(Günler.Cumartesi);
      test++;//test++; /* satırın 2. bölümü açılırsa başa döner */
      test.writeln();
}

Dip Not: Bu başlıktaki bir çok öğeyi belki de Enum'u Anlamak (http://ddili.org/forum/thread/816) başlığına taşımalıyız, ne dersiniz?

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

March 09, 2013

Alıntı (Salih Dinçer):

>

meğer son elemanı yutuyormuş.

Evet, enum'larda böyle bir sorun var. Sınır belirleyen başka olanaklarda sondaki değer hep aralığın dışında kalıyor ama enum.max aralığa dahil. Aslında enum.end gibi başka bir nitelik daha gerekiyor gibi... Ama aşağıda senin kodunda da görüldüğü gibi bu da çözüm değil.

Alıntı:

>
>         for(T x = T.min; x <= T.max; x++) {
> ```


T'nin int olduğunu düşünelim ve T.max==int.max olsun. O döngü sonsuza kadar takılır, değil mi?

Alıntı:
> Ama anlayamadığım bir şey de 'main()' içinde 'foreach()' ile kullandığınızda yine aynı çıktıyı almanız...

Yani şu kod Pazar'ı da yazdırıyor diyorsun:

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


Öyle çünkü foreach aralıktaki bütün elemanlar için işletilir. EnumMembers enum'un son değerini de içeren bir aralık oluşturur. Bizim yaptığımız gibi ++ işleciyle değil. Zaten enum değerleri arasında boşluk olsa ++ işlemez. EnumMembers öyle değil.

Alıntı:
> Bu başlıktaki bir çok öğeyi belki de Enum'u Anlamak (<http://ddili.org/forum/thread/816>) başlığına taşımalıyız, ne dersiniz?

Bu konuda konuşuldukları için bütünlük açısından bunun parçası olarak kabul edilmeliler. Örneğin, son yazdığın yazı bile "Yukarıdaki kodu" diye başlıyor. O zaman o kodu içeren yazıyı da mı seçip başka konuya taşımalıyız? Ya o da bir biçimde öncekilere bağlıysa? :) Bence daha iyisi, çok sayıda ama kısa konular açmak. Daha sonradan bir şeyleri arayınca sayfalar süren bir konu içinde dolaşmak kolay olmuyor.

Konuyu sen açtığın için senin yazdığın bir yazıyı örnek vereyim: Bu konu içinde "Konuyla alakasız ama" diye başlattığın bir yazı da var. ;)

Ali

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

Alıntı (acehreli):

>

T'nin int olduğunu düşünelim ve T.max==int.max olsun. O döngü sonsuza kadar takılır, değil mi?
Sıralı giden enum'lar için kim işaretli veri türü kullanır ki...:)

Bu durumda sözleşmeli programlama yapmaktan başka aklıma bir şey gelmiyor. Ama enum'un ismi bana tür olarak geliyor ve şu ana kadar edindiğim bilgiler ile iki nokta üst üste (''enum'' Günler:'')'den sonraki tür değerini sorguya tabi tutamıyorum:

   import std.typetuple;

   template testType(T) {
     alias TypeTuple!(int, byte, short, long) types;
     bool test() {
         foreach(t; types) {
             //if(typeid(T) is typeid(t))/*
             if(is(T == t))//*/
                 return false;
         }
         return true;
     }
     enum testType = test();
   }

   auto enumMembers(T)() in {
     assert(testType!T, "\n\n\t"
                        "You should use unsigned data types!\n");
   } body { //*/{
     string[] result;
     bool casting = true;

     for(T x = T.min; x <= T.max; x++) {
       auto value = appender!string();
       formattedWrite(value, "%s", x);
       foreach(char c; value.data) {
         if(c < 0x2F) { // içinde parantez varsa görmezlikten gel
           casting = false;
           break;
         }
       }
       if(casting) result ~= value.data;
       casting = true;
     }
     return result;
   }

import std.stdio;

void main() {
 enum Günler: uint {
   Pazartesi = 2, Salı=3, Çarşamba=5, Perşembe=7, Cuma=11, Cumartesi=13, Pazar=17
 }
 writefln("%-(%s, %)", enumMembers!Günler);
}

Neyse, bu arada bir geliştirme daha yaptım. Hani olur ya üyeler arasındaki değerleri sıralı olmaz. Bu durumda 'foreach()' ile yaptığımız sıralı mantık fena halde çuvallar. Çünkü enum'un üyesi olmayan değerleri (örn. ''cast(Günler)4'') döndürmeye başlıyor. Bunu ise çok basit bir şekilde içinde alfasayısal olmayan karakterlere rastladığında result dizgesine eklemeden önleyebiliyoruz.

Teşekkürker...

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

March 10, 2013

Az önce std.random'a bakıyorken std.traits (https://github.com/D-Programming-Language/phobos/blob/master/std/traits.d#L4539) içinde isUnsigned isminde bir şablon dikkatimi çekti.:
Alıntı (traits.d):

>
> /**
> Detect whether $(D T) is a built-in unsigned numeric type.
>  */
> template isUnsigned(T)
> {
>     enum bool isUnsigned = is(UnsignedTypeOf!T) && !isAggregateType!T;
> }
> ```

>
Bu ne güzel şablonmuş öyle...:)

İşimize yarıyor ve çok güzel çalışıyor. Zannedersem bunun sebebi IntegralTypeOf şablonu içindeki şu kısım:

static if (is(T == enum))
alias .IntegralTypeOf!(OriginalType!T) IntegralTypeOf;



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

Alıntı (Salih Dinçer):

>

Sıralı giden enum'lar için kim işaretli veri türü kullanır ki...:)

Aynı sorun işaretsiz türlerde de var. .max'ı bir arttırınca tekrar .min'den başlar. Şu döngü hiç sonlanmaz:

import std.stdio;
import std.conv;

auto foo(T)() {
   string[] result;
   for(T x = T.min; x <= T.max; x++) {
       result ~= x.stringof;
   }
   return result;
}

enum E : size_t { a = size_t.max - 2, b, c }

void main()
{
   foo!E();
}

Alıntı:

>

Bu durumda sözleşmeli programlama yapmaktan başka aklıma bir şey gelmiyor.

EnumMembers'ı nasıl yazmışlar acaba?

Alıntı:

>

iki nokta üst üste (''enum'' Günler:'')'den sonraki tür değerini sorguya tabi tutamıyorum:

std.traits.OriginalType'mış:

import std.traits;
// ...
   assert(is(OriginalType!E == size_t));

Ali

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

March 10, 2013

Alıntı (acehreli):

>

EnumMembers'ı nasıl yazmışlar acaba?
Çok fena yapmışlar...:)

template EnumMembers(E) if (is(E == enum)) {

   template WithIdentifier(string ident)  {
       static if (ident == "Symbolize") {
           template Symbolize(alias value) {
               enum Symbolize = value;
           }
       } else  {
           mixin("template Symbolize(alias "~ ident ~") {"
                ~"    alias "~ ident ~" Symbolize;"
                ~"}");
       }
   }

   template EnumSpecificMembers(names...)  {
       static if (names.length > 0)  {
           alias TypeTuple!(
                   WithIdentifier!(names[0])
                       .Symbolize!(__traits(getMember, E, names[0])),
                   EnumSpecificMembers!(names[1 .. $])
               ) EnumSpecificMembers;
       } else {
           alias TypeTuple!() EnumSpecificMembers;
       }
   }
   alias EnumSpecificMembers!(__traits(allMembers, E)) EnumMembers;
}

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