February 15, 2010

Şablonlar çok güzel bir olanak ve C++'dakilerden çok daha güçlü.

Şablorlar dersini mutlu mutlu yazarken bir sorunla karşılaştım. Şimdi Digital Mars haber grubundan sordum bakalım mantıklı bir açıklaması varmıymış...

Sorun şu: Girişten istediğim türde bir değer okuyan bir şablon yazıyoruz:

import std.cstream;


T giriştenOku(T)(string soru)
{
   dout.writef(soru, ": ");

   T cevap;
   din.readf(&cevap);

   return cevap;
}

void main()
{
   auto yaş = giriştenOku!int("Yaşınız?");
}

int, double, kendi türlerimiz, vs. için gayet güzel çalışıyor. Ama string için çalışmıyor. string'in elemanları 'immutable char' oldukları için, şablon içindeki 'din.readf' çağrısı parçalama hatasına (segmentation fault) neden oluyor.

Mantıklı... O zaman şablonların özelleme (specialization) olanağından yararlanarak string için özel bir tanımını veriyoruz:

T giriştenOku(T : string)(string soru)
{
   // ... öncekinin tekrarı olabilir; ama .idup döndürmesi gerek:
   return cevap.idup;
}

'(T : string)', bu tanımın şablonun string özellemesi olduğunu belirtiyor.

Sorun bu noktada ortaya çıkıyor: dmd char[] türü için de aynı özellemeyi seçiyor ve bu sefer de sonundaki .idup, char[] için sorun oluşturuyor.

Sorunlu bütün bir program:

import std.cstream;

T giriştenOku(T)(string soru)
{
   dout.writef(soru, ": ");

   T cevap;
   din.readf(&cevap);

   return cevap;
}

T giriştenOku(T : string)(string soru)
{
   dout.writef(soru, ": ");

   T cevap;
   din.readf(&cevap);

   return cevap.idup;
}

void main()
{
   auto isim = giriştenOku!string("İsminiz?");
   auto adres = giriştenOku!(char[])("Adres?");
   auto yaş = giriştenOku!int("Yaşınız?");
}

İsim için '!string', ve adres için '!(char[])' kullandığıma dikkat edin. Her ikisi için de özelleştirme seçiliyor ve program char[] durumundaki .idup için derlenmiyor.

Tabii aslında kod tekrarını azaltmak için asıl özelleme şöyle:

T giriştenOku(T : string)(string soru)
{
   return giriştenOku!(char[])(soru).idup;
}

Yani string özellemesinde, genel tanımı char[] için kullanmayı umuyorum ama olmuyor.

Çözüm: std/conv.d dosyasının içine bakıyorum ve bu işi to!string için nasıl hallettiklerini öğreniyorum. Çok güzel değil... :) D'nin koşullu derleme olanaklarından yararlanıyorlar: 'static if'...

Ben de şablonların koşullu derleme olanağına da başvuruyorum ve sonunda herşey halloluyor. Çalışan program şöyle:

import std.cstream;

T giriştenOku(T)(string soru)
{
   dout.writef(soru, ": ");

   T cevap;
   din.readf(&cevap);

   return cevap;
}

T giriştenOku(T : string)(string soru)
   if (is (T == string))          // <-- GEREKLİ
{
   return giriştenOku!(char[])(soru).idup;
}

void main()
{
   auto isim = giriştenOku!string("İsminiz?");
   auto adres = giriştenOku!(char[])("Adres?");
   auto yaş = giriştenOku!int("Yaşınız?");
}

Ama bu da çok saçma çünkü o özellemede şöyle bir anlam var: "bu, T'nin string olduğu durum için özellemedir; ama bunu T'nin string olduğu durumda göze al." :)

Bir bozukluk var. Haber gruplarında sordum; belki bilinen bir hatadır veya bir açıklaması vardır.

Ali

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

February 16, 2010

Evet, galiba bilinen bir derleyicisi hatasıymış. Hatayı 'shared' için açmışlar ama benim karşılaştığım 'immutable' konusuyla aynı olmalı:

http://d.puremagic.com/issues/show_bug.cgi?id=3750

Ali

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