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.