Alıntı (zafer):
>
> immutable dosyaYeri = dosya.tell(); // <-- değişkende sakla
> scope(exit) dosya.seek(dosyaYeri, SEEK_SET);
> ```
>
> Bu kodlarla amacımız metotun çıkışında dosyayı ilk haline getirip bırakmak ama buna neden ihtiyaç duyduk
> gerçi bu sayde scope()'u tanımış olduk ama işlemin sonunda dosya.close() ile dosyayı kapatmak daha doğru
> olmaz mıydı?
Bu işlev dosyayı kendisi açmadığı için kapatması da doğru olmazdı.
Tabii işlevi dosyayı kendisi açacak biçimde de tasarlamış olabilirdik. Dosya ismini verirdik, açardı, pakedi okurdu, ve döndürürdü. (Ara not: Ben o zaman bile dosya.close()'u açıkça çağırmazdım. Bir C++ programcısı olarak programları sonlandırıcı işlevler etrafında düşünüyorum. File'ın sonlandırıcısı zaten dosyayı kapattığı için açıkça kapatmaya gerek yok. Açıkça kapatmak, hemen tekrar örneğin başka bir erişim hakkı ile açılacaksa şarttır. Ama açıkça kapatılmasında da hiç sakınca yoktur tabii.)
Ancak, işlevin dosya ismi almasını beğenmemiştim:
* Dosya açmak göreceli olarak masraflıdır. Zaten açık bir dosya varsa onu kullanmak daha etkin olur. (O yüzden de dosyayı baştaki durumuna getirmek için yapmamız gereken tek şey seek()'i çağırmak.)
* Bizi çağıran kodun dosyayı zaten açmış olmasını beklemek mantıklıdır çünkü ID3v1 olup olmadığına ancak dosyanın bazı yerlerini okuyarak karar vermiştir. Yani bizi çağırdığına göre dosyayı açıp içine zaten bakmıştır.
* En önemlisi basitlik. (Basitlik yazılım tasarımlarının en baş ilkesi olmalıdır.) İşlevin şimdiki tanımı şöyle: "dosyanın ID3v1 pakedini okur ve döndürür; paket yasal değilse hata atar." Eğer dosya ismi alsaydı birazcık daha karmaşık olurdu: "dosyayı açar, ... vs. ...". Ama bu sefer dosya açılamadığında da hata atması gerekirdi. Yani işler azıcık da olsa karmaşıklaşmış olurdu. (Bu maddenin o kadar inandırıcı olmadığını kabul ediyorum ama bana File alan işlev daha az karmaşık geliyor. En azından içinde dosya açma satırı yok. :))
Bunlara karşılık senin fikrin de geçerli: dosya ismini alıp dosyayı açıp kapatsak seek() ile baştaki durumuna getirmek gibi bir derdimiz olmazdı. O da kabul. Belki de beni yönlendiren şey gerçekten de dosya açma masrafıydı. Ayrıca işletim sistemleri aynı anda belirli sayıda dosyadan fazlasını açtırmazlar. Zaten açıksa onu kullanmak iyidir.
Alıntı:
>
>
> ID3v1Pakedi[1] paketler;
dosya.rawRead(paketler);
ID3v1Pakedi paket = paketler[0];
> Burada paketler isminde tek elemanlı bir dizi oluşturuyoruz ve rawRead() metoduna bu diziyi gönderiyoruz.
Biraz garip yapmışlar: rawRead() şablon olduğu için her tür dizi olarak okuyabiliyor. Ama nedense tek değişkene okuyan yüklemesini yapmamışlar. Onun için tek paket bulunduğunda bile dizi olarak tanımlamak gerekiyor.
Alıntı:
> Sonrasında ise dizideki tek elemanı bir pakete aktarıyoruz.Bunun yerine paket isminde bir değşken oluşturup göndersek olmaz mı?
Tek değişkene yukarıdaki nedenden okuyamadık. Ama söylediğinin son bölümünü öyle yaptık zaten: paket isminde değişken oluşturup onu gönderdik. Olsa olsa, ondan vazgeçip hep paketler[0]'ı kullanırdık:
enforce (paketler[0].TAG == "TAG",
format("'%s', bir ID3v1 dosyası değil!", dosya.name()));
return paketler[0];
paket değişkenini okunaklılığı arttıracağını düşünerek eklemiştim. Yoksa bir tane olduğunu bildiğimiz pakedi dizi gibi kullanmak garip gelmişti. Ama bunda bir tane kopya eksik olduğu için daha hızlı işleyecektir. (O konuda da derleyiciye güvenmiştim: Derleyici, paket değişkenini gerçekten oluşturmak yerine doğrudan paketler[0]'ı kullanabilir. Tabii bunu programın davranışında bir farklılığa neden olmayacağını kanıtlayabilirse yapar.)
Yapılabilse, daha iyisi şu olurdu:
alias paketler[0] paket; // <-- derleme HATASI
O zaman paketler[0]'a paket ismini vermiş olurduk. Ama "bir ifade alias yapılamaz" gibi bir hata mesajıyla derlenemiyor.
Başka bir hayal, paket'in paketler[0]'ın referansı olduğunu belirtmek olurdu:
ref ID3v1Pakedi paket = paketler[0]; // <-- derleme HATASI
Ama D'de öyle yerel değişken referansları yok. (C++'ta & karakteri ile olabilirdi.) (D'de işlev parametreleri ref olabiliyor.)
Aklıma gelen son yöntem gösterge kullanmak:
ID3v1Pakedi * paket = &paketler[0];
enforce (paket.TAG == "TAG",
format("'%s', bir ID3v1 dosyası değil!", dosya.name()));
return *paket;
Baştaki paket değişkeninin oluşturulma masrafından kurtulmuş olduk. Bunun gerçekten kazançlı olup olmadığı denenerek bulunabilir.
Ama bence hiçbir program dosyanın sonundan ID3v1 pakedi okuyan işlevin içindeki bir kopya yüzünden yavaşlamaz. Dosya ne de olsa bir işlemde kullanılacaktır. O işlemler yanında 128 baytlık basit bir struct kopyası farkedilmez. :)
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]