July 20, 2010

d-ofis'i daha yeni indirebildim. Benim de hoşuma gitti! :)

Her zaman olduğu gibi, gereksiz olsa da bir kaç not:

  • Ben 4 boşluklu girintilere fazla alışmışım; 2 boşluk çok sıkışık geliyor :)

  • module isminin dosya ismi ile aynı olması şart değil (galiba :)); ama ben olsam yine de baş harfini dosyanın ismiyle aynı olsun diye küçük v yapardım

  • std.stdio.File'ı kullanıyoruz ve cstream gidici olduğuna göre doğrusu da o... Ama, std.stdio.File bir yapı olduğu için onu new ile oluşturmaya gerek yok. Hatta aslında close'u da çağırmaya gerek yok; çünkü 'dosya' nesnesi tabloOluştur'dan çıkarken hemen sonlanacak:

void tabloOluştur()
{
 auto dosya=File("deneme.txt","a");
 dosya.writeln(tab_adı);
}

(Dediğim gibi, sohbet olsun diye gerekli gereksiz yorum yapıyorum; çünkü new'lü ve close'lu kodda da bir sakınca yok aslında. :))

  • Ben her zaman için sol tarafa yazılan ++ işlecini öneririm:
   ++kolon_sayı;

kolon_sayı gibi bir int'te hiçbir şey farketmez ama daha kapsamlı türlerde, sağ tarafa yazılan ++ işleci daha pahalıdır. Yeni işleç yükleme düzeneğinde sağa yazılan ++ yüklenemiyor bile; çünkü şu kod olarak işletiliyor: '(auto t = e, ++e, t)'. O da, geçici bir 't' nesnesi kullandığı için genelde daha yavaştır.

(Aynısı -- işleci için de geçerli.)

  • foreach'e bir kere alışırsan bir daha for yazmak istemeyeceksin ;) Örnek:
 foreach (i; 0 .. 90) {
     dosya.write(ÇizgiŞekli);
 }

Bazı durumlarda da std.string modülündeki 'repeat' işlevi işe yarayabilir:

 dosya.write(repeat(ÇizgiŞekli.idup, 90));

Ali

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

July 21, 2010

Ali Beyin dediklerini kodun anlamlarını değiştirmediği için sizinde bilgisayarınızın gerektiği gibi çalışmamasından dolayı kendim yaptım ve yolladım.

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

July 21, 2010

canalpay,teşekkür ederim.

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

July 24, 2010

Bilgisayarım düzeldi.Yarın kodlamaya devam edeceğim.

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

January 02, 2011

Alıntı (canalpay:1279567641):

>

Kişiler

No|İsim|Soyisim

0|Kadir Can|Çelik
1|Can Alpay|Çiftçi
2|Ali|Çehreli

Ali
Çehreli

İstenen görünümü kazandırdım.Arama işlevine geldi sanırım sıra.

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

January 02, 2011

Çok güzel. :)

Daha iyi olması için bir kaç not aldım. Bunların bazılarını sen de biliyorsundur aslında... :) Bunları yazıyorum diye kötü olduğunu düşündüğümü sanma. Yalnızca "şöyle olsa daha iyi olur" havasında yazıyorum.

  1. İlk olarak dikkatimi çeken, bilgilerin deneme.txt dosyasına sürekli olarak eklenmeleri oldu.

(Not: Sanırım bu konu, (4) numaralı madde halledilmeden önce halledilemez.)

Programlarda işlemleri olabildiği kadar "ya oldu ya olmadı" (transactional) şeklinde gerçekleştirmek de isteriz. Örneğin dosyaya yazarken bir hata olsa, dosyaya yarım yazılmış halde kalabiliriz.

Güvenli bir yöntem, verileri önce geçici bir dosyaya (örneğin "deneme.ara.txt" isminde bir dosyaya) yazmak, ve ancak herşey yolunda gittiyse ismini "deneme.txt" olarak değiştirmektir.

D'nin başka dillerde bulunmayan çok güzel bir olanağı var: 'scope'. Andrei de doğal olarak onu özellikle belirtmekten hoşlanıyor. :) Şu sayfa biraz fazlaca uzun ama "scope(exit), scope(success), ve scope(failure)" başlığı 'scope''u anlatıyor:

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

  1. "deneme.txt", programda birden fazla noktada geçiyor. Bunun bazı sakıncaları var: Öncelikle bu, açıkça kod tekrarıdır; ikincisi, tablo başka bir ortama yazdırılamaz. Örneğin en azından başka bir dosyaya yazdırılabilmeli.

Burada en kolayı, veri ile yazdırma işlemini birbirlerinden ayırmaktır. veri'ye bir yazdırıcı veririz ve "şu yazdırıcıyı kullanarak yazdır" diyebiliriz. Onun da bir OutputRange olması çok yararlı olur.

  1. Bir öncekine bağlı olarak, aslında kolon_sayı ve kolon_sayı_yedek üyelerinin veri ile ilgileri bulunmuyor. Onlar, yazdırma işleminin durumu ile ilgili geçici değişkenler. Yazdırma işi veri'den ayrıldığında sanırım onlar da veri'den çıkacaklar

  2. Veriler dosyada yaşıyorlar. Bunun bir sakıncası yavaşlıktır. Bence en iyisi, bütün veriyi bellekte, örneğin bir eşleme tablosunda veya bir dizide oluşturmak ve en sonunda birisi "kaydet" dediğinde dosyaya yazmaktır. İşte (1) numaralı maddeki scope'tan da şimdi yararlanabiliriz. "kaydet" dendiğinde her veri ara dosyaya yazılır, vs.

Burada üstü kapalı olan bir gerçek var: bütün veri parçaları aslında dizgi. Sonuçta herşey dosyaya dizgi olarak yazılıyorlar. Bu yeterli olabilir; hatta veri'nin temel amacı zaten budur da... Ama belki de veri'yi herhangi bir türle kullanmayı da düşünebiliriz:

class Kişi
{
   // ...
}

Sonra veriEkle() de o türü alabilir... Ama bu noktada belki de gereksizce geliştirmeye çalışıyorum... :/ Belki de sınıfın amacı bu kadar esnek olmak olmayabilir.

  1. main'in içindeki adımlardan anlaşıldığı gibi, programcı olayların gelişimi ile çok ilgilenmek zorunda kalıyor.

En azından, main içinde bazı adımların tekrarlandıkları görülebilir ve bunlar bir işleve taşınabilir (uyarı: derlemeden yazıyorum):

void kişiEkle(veri tablo, string ad, string soyad)
{
   tablo.veriEkle(ad);
   tablo.veriEkle(soyad);
   tablo.satırBitti();
}

Böylece main içindeki kodlar kolaylaşmış olur. Kodların tekrarlandıklarını farkedip onları böyle işlevlere taşımak programcılığın hep yapılan işlemlerindendir. :)

  1. Yukarıdaki gözlemler altında, sınıfın ismi olarak veri artık uygun olmamaya da başlamış. Bana sanki veri çok alt düzey bir isim gibi geliyor. Tablo adını taşıyan bir üyesi olduğuna göre bu haliyle aslında belki de bir VeriTablosu denmeli...

Ama dediğim gibi, bence aslında çok güzel. Hatta amacı karşılıyorsa hiçbir değişiklik de yapılmamalıdır. :)

Eğer herhangi bir yerini değiştirmeye karar verirsen ve takıldığın bir yer olursa burada (ama belki de başka bir başlık altında) konuşalım.

Ali

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

January 03, 2011

Gerçekten çok teşekkür ederim.Bu benim geliştirdiğim ilk projelerden biri ve acemiliklerim oluyor.Sizler gibi uzmanların tavsiyelerine göre yazılıma şekil vereceğim.Benim işim kod yazmak gibi yani.

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

January 03, 2011

Dosya olayıyla ilgili olarak vtOluştur işlevini yazdım.Fakat hatalı.Bakabilir misiniz?

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

January 03, 2011

vtOluştur içindeki 'dosya' isminin geçerliliği o işlevle sınırlıdır. Üstelik, orada oluşturulan File nesnesinin de yaşamı o işlevden çıkıldığında sona erer.

Derleme hatasının nedeni, tabloOluştur ve diğer işlevlerde kullanılan dosya'nın ne olduğunun bilinmiyor olmasıdır.

class veri
{
   const char[] tab_adı;
   int kolon_sayı;
   int kolon_sayı_yedek;
   int id;
   string dosyaAdı;

/* ... */

   void vtOluştur()
   {
	File dosya=File(dosyaAdı,"a");
   }
/* ... */
   void tabloOluştur()
   {
       dosya.writeln(tab_adı);   // <--- Bilinmiyor!
   }

/* ... */

void main(){

veri vt=new veri("Kişiler");

vt.vtOluştur();

Bu hatayı gidermek için dosya'yı verinin bir üyesi yapabilirsin:

class veri
{
/* ... */
   File dosya;

   this(const char[] tab_adı)
   {
       /* ... */
       this.dosya = File(dosyaAdı,"a");
   }

   void vtOluştur()
   {}

Tabii vtOluştur'a da gerek kalmamış olur. Hmmm... Yoksa ona gerek var mı?

Yani tek bir veri sınıfının birden fazla tablosunun bulunmasını mı istiyoruz, yoksa veri zaten tek bir tabloyu mu modelliyor?

Ali

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

January 03, 2011

Amacı hatırlamaya çalışıyorum: veri tabanı gibi çalışan bir sınıf oluşturmak istiyoruz. Bu sınıfın nesnelerinin içine attığımız veriler bir dosyada belirecekler.

Bir soru: Daha önceden dosyada bulunan veriler de geçerli olacaklar mı? Yani "ali" verisine yazdığımızda var olan veri mi değişecek, yoksa dosyanın sonuna yeni bir "ali" mi eklenecek?

Dosya içindeki belirli bir kayıda gitmek çok zordur. Özellikle metin halindeki dosyalarda kayıtların uzunlukları da eşit olmayacaklarından, "'ali' kaydını bul" gibi bir işlem için bütün dosyanın baştan taranması gerekir. (Hızlandırıcı yöntemler de kullanılabilir ama bir sürü karmaşıklık getirir.)

Konuya bir kere de elimizdeki araçlarla başlayarak bakalım. Zaten eşleme tabloları var. O neden yetmiyor? Çünkü kaydetme olanağı yok. Kabul.

O eksikliği veri isminde bir sınıfla gidermek istiyoruz. O da kabul. Yani bu sınıfın yararı, yapılan her değişiklikte dosyanın da değişmesi oluyor, öyle mi?

Tabii veri'de bir eksiklik var: verilere nasıl erişileceğini hiç konuşmadık. Acaba perde arkasında bir eşleme tablosu kullanmak yararlı olur mu? Şöyle bir şey?

class veri
{
   Kişi[string] veri;
   /* ... başka üyeler */

   void ekle(string anahtar, Kişi değer)
   {
       veri[anahtar] = değer;
       kaydet();
   }

   Kişi eriş(string anahtar)
   {
       return veri[anahtar];
   }

   /* ... */
}

Yani verinin depolanmasının bir eşleme tablosu halleder, biz de değişikliklerde dosyayı baştan yazarız. (Sonuna eklemek olmuyor tabii ki; programı her çalıştırdığımızda dosya aynı kayıtlar tekrarlanarak büyüyor.)

Tabii şimdi de konu kaydet()'in nasıl yazılması gerektiğine geliyor. Kişi nasıl bir türdür? Bu sınıf her türle çalışmalı mıdır? (Bence her türle çalışmasını istemiyorsun. Bu her sütunun string olduğu bir tablo. Yani bunun üstünde bir soyutlama ile ilgilenmiyorsun.)

Bence en azından şöyle olmalı (bu fikirde kararlıyım :) : Bütün tablo, bellekte durmalı. Tablo, kullanıcıların veriEkle, satırBitti, vs. gibi işlevleri doğru çağırmasına dayanmamalı. Kullanıcılar bize tutarlı bir nesne vermeliler, biz onları depolamalıyız ve ancak ya kullanıcı söylediğinde, veya otomatik olarak dosyaya kaydetmeliyiz.

Örnek:

module veri;
import std.stdio;
import std.string;
import std.file;

class veri
{
   string[][] kayıtlar;
   string dosyaAdı;

   this(string dosyaAdı)
   {
       this.dosyaAdı = dosyaAdı;
   }

   void ekle(string[] kayıt)
   {
       kayıtlar ~= kayıt;

       /* Otomatik kayıt yerine kaydet()'i kullanıcının açıkça çağırmasını da
        * isteyebiliriz */
       kaydet();
   }

   void kaydet()
   {
       auto geciciDosyaAdı = dosyaAdı ~ "gecici";
       auto dosya = File(geciciDosyaAdı, "w");
       scope(failure) remove(geciciDosyaAdı);

       /* ... burada kayıtlar yazılır; ben öylesine bir şey yazıyorum  */
       foreach (kayıt; kayıtlar) {
           foreach (sütun; kayıt) {
               dosya.writeln(sütun);
           }
           dosya.writeln();
       }

       rename(geciciDosyaAdı, dosyaAdı);
   }
}

void main()
{
   auto v = new veri("deneme.txt");
   v.ekle(["ali", "ankara" ]);
   v.ekle(["veli", "van"]);

   /* Veya dinamik bir kayıt oluşturarak */
   string[] kayıt;
   kayıt ~= "zeynep";
   kayıt ~= "zonguldak";
   v.ekle(kayıt);
}

Orada scope'un da bir örneğini gösterdim. Geçici bir dosyaya yazıyoruz ve en sonunda geçici dosyanın ismini asıl dosyanın ismi olarak değiştiriyoruz.

Ama eğer bir hata olursa (yani "failure" durumunda), geçici dosya remove ile otomatik olarak silinecek. scope(failure)'ın yararı o.

Ali

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