Thread overview
Hızlı toString()
Oct 09, 2012
Salih Dinçer
Oct 09, 2012
Salih Dinçer
Nov 30, 2012
Salih Dinçer
Dec 02, 2012
Salih Dinçer
Jun 05, 2013
Salih Dinçer
October 10, 2012

Teşekkürler hocam, örnekleri deneyeceğim hatta bunu SDL'ye uyarlayıp görselleştirebiliriz de...:)

Belki konuyla çok alakalı değil ama bazı nesneleri varsayılan toString() işlevini çağırdığımızda sadece nesnenin ismi/türü falan geliyor. İçeriği gelmediğini gördüğümde de mecburen kendi override'mı yapıyorum. Bunu sebebi ne olabilir?

Çünkü o an geliştirme yapıyorsunuz ve nesnenin içindeki üyeleri şöyle bir göreyim istiyorsunuz. Yani gidip vakit kaybetmemek için bize bunu nesne.writeln() ile gösterse ne iyi olur. Tabi çoğunlukla öyle ama bazen olmuyor nedense...

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

October 10, 2012

Alıntı (acehreli):

>

Yapılarda oluyor ama sınıflarda olmuyor, değil mi?
Evet, yani sanırım ve tam olarak emin değilim...:)

Belki yapılarda override yapmaya ihtiyaç duymamamız ve onların içinde böyle bir varsayılan toString() işlev olmayışından dolayıdır. Yine karşılaştığım zaman, eğer yapı harici bir durum ise burada dillendirmeye çalışacağım.

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

October 10, 2012

Yapıların ve sınıfların toString() işlevlerinin tasarımı hız açısından iyi değildir:

string toString() const
{
   // ... bir string oluştur ve döndür ...
}

Aslında mantık olarak doğrudur: Nesnenin string olarak ifadesi döndürülmektedir. Ancak, iç içe nesneler kullanıldığında bütün üyelerin toString()'lerinin çağrılmaları ve onların döndürdükleri string'lerden oluşan yeni bir string döndürülmesi yavaş kalabilir.

Aşağıdaki programdaki Poligon nesnesi RenkliNokta'lardan oluşuyor. RenkliNokta da Renk ve Nokta'yı bireştiriyor:

import std.stdio;
import std.string;
import std.format;
import std.array;

struct Nokta
{
   int x;
   int y;

   string toString() const
   {
       return format("(%s,%s)", x, y);
   }
}

struct Renk
{
   ubyte r;
   ubyte g;
   ubyte b;

   string toString() const
   {
       return format("RGB:%s,%s,%s", r, g, b);
   }
}

struct RenkliNokta
{
   Renk renk;
   Nokta nokta;

   string toString() const
   {
       return format("{%s;%s}", renk, nokta);
   }
}

struct Poligon
{
   RenkliNokta[] noktalar;

   this(RenkliNokta[] noktalar...)
   {
       // NOT: BU KOD HATALI! Aşağıda 6 numaralı yorumda açıklanıyor.
       this.noktalar = noktalar;
   }

   string toString() const
   {
       return format("%s", noktalar);
   }
}

void main()
{
   auto p = Poligon([ RenkliNokta(Renk(10, 10, 10), Nokta(1, 1)),
                      RenkliNokta(Renk(20, 20, 20), Nokta(2, 2)),
                      RenkliNokta(Renk(30, 30, 30), Nokta(3, 3)) ]);

   writeln(p);
}

main() içindeki writeln() çağrısı, her RenkliNokta için üç string'den toplam dokuz string oluşmasına neden olur. O da, akıllıca davrandığımız ve format'tan yararlandığımız için öyledir... Yoksa, aşağıdaki gibi eklemeler daha da fazla string oluşmasına neden olurdu:

import std.conv;
// ...
struct RenkliNokta
{
   Renk renk;
   Nokta nokta;

   string toString() const
   {
       // Beş string'in eklenmesi ve altıncı bir string'in döndürülmesi!
       return "{" ~ renk.to!string ~ ";" ~ nokta.to!string ~ "}";
   }
}

(Not: Tabii dizi eklemelerinde D olabildiğince hızlıdır. Sonunda boş yer olan diziye eklemek hızlı bir işlemdir.)

Phobos'a bir kaç sürüm önce eklenen ve şimdilik yalnızca BigInt tarafından kullanılan bir toString() yüklemesi daha var(mış). Aslında ben duyuyordum ama daha önce hiç denememiştim.

Bu olanak aslında formattedWrite'a ait: C++'ın akımlarındaki mantığa sahip. Tam olarak da std::ostringstream'in eşdeğeri olarak görülebilir. ostringstream, kendisine yazılan değerleri içindeki tek std::string'e ekler:

// C++ kodu
   ostringstream cikis;
   cikis << 42 << "merhaba";  // icindeki string bUyUr
   cout << cikis.str();       // olusturdugu string'e sonunda .str() ile erisilir

D'de bunu sağlayan toString() yüklemesi şöyle:

   void toString(scope void delegate(const(char)[]) hedef) const
   {
       // ... formattedWrite ile hedef'e yaz ...
   }

(İngilizce belgelerde 'hedef' yerine 'sink' deniyor.)

Çok korkutucu görünüyor :) ama kullanımı bildiğimiz toString() kadar basit. Tek yapılması gereken, format()'ın ürettiğini return ile döndürmek yerine, formattedWrite ile hedef'e yazdırmak:

struct Nokta
{
// ...
   void toString(scope void delegate(const(char)[]) hedef) const
   {
       formattedWrite(hedef, "(%s,%s)", x, y);
   }
}

struct Renk
{
// ...
   void toString(scope void delegate(const(char)[]) hedef) const
   {
       formattedWrite(hedef, "RGB:%s,%s,%s", r, g, b);
   }
}

struct RenkliNokta
{
// ...
   void toString(scope void delegate(const(char)[]) hedef) const
   {
       formattedWrite(hedef, "{%s;%s}", renk, nokta);
   }
}

struct Poligon
{
// ...
   void toString(scope void delegate(const(char)[]) hedef) const
   {
       formattedWrite(hedef, "%s", noktalar);
   }
}

Sonuçta, main()'deki writeln(p) çağrısı toString'in bu yüklemesini algılıyor, sonuna eklemekte olduğu kendi içindeki tek string'i hedef olarak kullanan bir temsilci oluşturuyor, ve o temsilciyi 'p' nesnesinin toString()'ine gönderiyor. formattedWrite da öyle bir temsilciye eklemeyi bildiğinden bize yalnızca düzeni belirtmek kalıyor.

'hedef' elden ele bütün türlere geçtikçe eklenen karakterler hep aynı dizginin sonuna ekleniyor. Sonuçta da nesnelerin string karşılıkları çok daha hızlı bir biçimde oluşturulabiliyor.

(Bunu da kitabın uygun bir yerine eklemem gerekiyor.)

Ali

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

October 10, 2012

Yapılarda oluyor ama sınıflarda olmuyor, değil mi?

import std.stdio;

struct S
{
   int i;
   double d;
}

class C
{
   int i;
   double d;

   this(int i, double d)
   {
       this.i = i;
       this.d = d;
   }
}

void main()
{
   auto s = S(1, 2.2);
   auto c = new C(3, 4.4);

   writeln(s);
   writeln(c);
}

'S(1, 2.2)
deneme.C
'

Sanırım bunun nedeni, sınıflarda Object.toString diye bir işlevin varlığı ve Object düzeyindeyken ondan türemiş olan C'nin üyelerinin bilinemiyor olması. Object.toString'in tek yapabildiği de türün ismini yazdırabilmek. :/

Bunun çaresi var ama şu anda hatırlamıyorum. D forumlarında std.traits.EnumMembers diye aratırsan bir şeyler bulabilirsin. Onunla ilgili olduğundan emin gibiyim. :)

Sonuçta bütünÜyelerininDeğerleriniYazdır(nesne) gibi bir çağrı sağlanabilir.

Ali

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

November 30, 2012

Yine eski başlıkları bir bir hortlamaya başladım! Neyse ki bunlar o kadar eski değil...:)

Bu başlığa da gerçekten önem veriyorum...

Bir süredir formattedWrite() kullanıyordum. Her ne kadar toString()'leri test amaçlı kullansam da bir temsilci ile vagon gibi değerleri üretip lokomotife takmak çok çok hoş. Henüz ezberime girmedi ama bir kaç pratik ile aday görünüyor...

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

November 30, 2012

Bu fırsattan yararlanarak kodumdaki bir hatayı düzelteyim. :)

Alıntı (acehreli:1349854334):

>
> struct Poligon
> {
>     RenkliNokta[] noktalar;
>
>     this(RenkliNokta[] noktalar...)
>     {
>         this.noktalar = noktalar;
>     }
> // ...
> }
> ```


Yukarıdaki kurucudaki ifade hatalıdır çünkü '...' ile bildirilen parametreyi oluşturan dizinin uzun süre yaşayacağına güvenilemez. Ne yazık ki noktaların bir kopyasını almak şarttır:

   this.noktalar = noktalar.dup;


Şansımıza aşağıdaki kullanımda hata yokmuş çünkü kullanıcı açıkça bir dizi oluşturarak çağırıyor:

Alıntı:
>
>
auto p = Poligon([ RenkliNokta(Renk(10, 10, 10), Nokta(1, 1)),
                   RenkliNokta(Renk(20, 20, 20), Nokta(2, 2)),
                   RenkliNokta(Renk(30, 30, 30), Nokta(3, 3)) ]);

(Yani, parametrenin etrafında köşeli parantezler var.) Oysa, '...' olanağından yararlanmak isteyen birisi kendisi açıkça dizi oluşturmadan da çağırabilirdi ve böyle bu olanağın asıl sunduğundan da yararlanmış olurdu:

   auto p = Poligon(RenkliNokta(Renk(10, 10, 10), Nokta(1, 1)),
                    RenkliNokta(Renk(20, 20, 20), Nokta(2, 2)),
                    RenkliNokta(Renk(30, 30, 30), Nokta(3, 3)));

O zaman otomatik olarak bir dizi oluşturulurdu ama işte o dizinin yaşamı ancak o satır süresincedir. İlk koddaki 'this.noktalar' geçersiz bir diziyi gösterirdi.

Böylece düzelttim. :)

Ali

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

December 02, 2012

İlginçmiş, böyle hassas noktalar olduğunu bilmiyordum. Ancak bu konuyu irdelemekte fayda görüyorum...

Şurada (http://ddili.org/forum/thread/1033) bir başlık açtım ve belki konuyu da dağıtmamış oluruz...:)

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

June 03, 2013

Bu konuyu "İşlev Göstergeleri, İsimsiz İşlevler, ve Temsilciler" bölümüne "delegate parametreli toString" başlığı altında ekledim:

http://ddili.org/ders/d/kapamalar.html

Ali

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

June 05, 2013

Teşekkürler, bu güncellemeyi şimdi hemen okuyorum...:)

Her ne kadar konuyu gayet iyi hatırlasam da kitaptaki konulara bayılıyorum. Hatta artık biz gönül verenler, bir blogda haftalık yazılar yazsak diyorum. Konu dağılmaması için ayrı bir başlıkta devam edelim isterseniz:

http://ddili.org/forum/thread/1180

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