Alıntı:
> Yazdığım test içindeki ifade replicate() metodunun dolduracağı genislik bilgisini aldığı ikinci değeri sıfırdan küçük bir değer oluyordu ve program patlıyordu tabi
Harika! :)
Alıntı:
> Birim testler önemli ve çok değerliler.
Hem de nasıl! :)
Alıntı:
> Diğer taraftan sanırım değer döndürmeyen metodlar için birim testleri yazamıyoruz doğru mu?
Teknik olarak yazamadığımız doğru değil. Aslında unittest blokları programda herhangi bir yere yazılabilirler. Derleyici basitçe o blokları da işletiyor (veya seçenek etkin değilse işletmiyor).
Değer döndürmeyen işlevlerin en azından yan etkileri vardır. Onlar da dolaylı olarak öyle test edilebilirler. Hatta bazen hatasız olarak işleyebilmesi bile test etmek için yeterli olabilir.
Burada akla bir soru gelebilir: ya işlevin yan etkisi kolayca denetlenemiyorsa? Sanırım bunun yanıtı şu: "eğer birim testlerini koddan önce yazarsanız tasarımlarınız daha iyi olur. Örneğin birim testini yazarken işlevin kolayca test edilebilir olmasını sağlamak ilerisi için kullanışlı olacaktır. Bunlar benim fikirlerim değil, TDD (test driven development) yönteminin savunduğu konulardan birisidir.
Alıntı:
> Ayrıca replicate() metodunun kendi içinde genişlik değerinin kontrolü yapması gerekmez mi diye soruyorum?
İki genişlik değerini düşünebiliriz:
/* ... */ replicate(S)(S s, size_t n)
/* ... */
-
s.length'e güvenilebilir çünkü s bir dizi olduğuna göre .length niteliği doğrudur. Dizi işlemleri bunu garanti ederler.
-
n'e güvenip güvenmeme konusu biraz daha karmaşık ve ilginç. Örneğin bu işlev aşağıdaki diziyi indeksler n'i kullanıyor:
/* ... */[n * s.length]
Ama replicate kendisi n'nin değerini doğrudan kullanmadığı için, eğer bir sorun varsa dizi indeksleme işlemi sırasında farkedilecektir. replicate'in "kendi edindiğim bu parametre değerini çağırdığım bir işleve göndermeden önce denetleyeyim" demesi fazlaca bir denetim kabul edilebilir.
Biz kendi C projelerimizde bunu uyguluyoruz: aracı işlevler parametrelerin NULL olup olmadığını yalnızca kendileri o göstergenin gösterdiğine erişirken kullanıyorlar. Eğer parametre olduğu gibi başka bir işleve gönderiliyorsa bu işlev ayrıca denetlemiyor.
Ayrıca Phobos daha yeterince olgun değil. Kod ileride değişebilir. :)
Son olarak, n'nin türü size_t olduğundan sıfırdan büyük olduğundan da eminiz tabii.
Alıntı:
> replicate() kodunu incelemek istedim ama bilmediğim o kadar çok şeyle karşılaştım ki bu sebele buraya taşıdım belki birlikte inceleriz.
Her tarafını açıklıyorum. :)
// (1)
/********************************************
Returns an array that consists of $(D s) (which must be an input
range) repeated $(D n) times. This function allocates, fills, and
returns a new array. For a lazy version, refer to $(XREF range, repeat).
*/
// (2) (3) (4) (5)
ElementEncodingType!S[] replicate(S)(S s, size_t n) if (isDynamicArray!S)
{
// (6)
alias ElementEncodingType!S[] RetType;
// (7)
// Optimization for return join(std.range.repeat(s, n));
// (8)
if (n == 0)
return RetType.init;
// (9)
if (n == 1)
return cast(RetType) s;
// (10) (11) (12) (13) (14)
auto r = new Unqual!(typeof(s[0]))[n * s.length];
// (15)
if (s.length == 1)
r[] = s[0];
else
{
// (16)
immutable len = s.length, nlen = n * len;
for (size_t i = 0; i < nlen; i += len)
{
r[i .. i + len] = s[];
}
}
// (17)
return cast(RetType) r;
}
(1) Açıklaması:
Alıntı:
> s'nin n kere tekrarlanmasından oluşan bir dizi döndürür (s bir giriş aralığı olmalıdır). Bu işlev yeni bir dizi için yer ayırır, onun içini doldurur, ve döndürür. Tembel olarak işleyeni için bkz. std.range.repeat.
(2) Dönüş türü: Elemanları S'nin eleman türü olan bir dinamik dizi (veya "dilim")
(3) İşlev şablonunun ismi replicate, tek şablon parametresine S diyoruz
(4) İşlevin parametreleri: S türünde s ve size_t türünde n
(5) "Sevgili derleyici, bu şablonu yalnızca S'nin dinamik dizi olduğu durumlarda göze al."
(6) Uzun uzun 'ElementEncodingType!S[]' yazmak yerine kısaca 'RetType' diyeceğiz
(7) Açıklama şunu ifade ediyor: Burada 'return join(std.range.repeat(s, n))' de yazabilirdik ama o işlev çağrısı için hız bile kaybetmeyelim diye 0 ve 1 durumlarında sonucu hemen döndüreceğiz:
(8) 0 kere tekrarlanacaksa boş dizi döndürüyoruz (dizilerin .init niteliği o dizi türünde boş dizidir)
(9) 1 kere tekrarlanacaksa s'nin kendisini döndürüyoruz
Oradaki 'cast(RetType)' tür dönüşümüne neden gerek olduğundan emin değilim. (?)
(10) Türünü açıkça yazmak istemediğimiz r isminde bir değişken tanımlıyoruz. Bu değişkenin bir dizi olduğunu da sağ taraftaki türünden biliyoruz tabii ki.
(11) Herhalde daha hızlı olacağını ölçmüş olduklarından, bu diziyi tekrar tekrar sonuna ekleyerek oluşturmak yerine gereken bütün yeri baştan ayırıp içini ondan sonra dolduracak biçimde oluşturmak istiyorlar. Onun için new ile yeterince büyük bir yer ayrılıyor.
(12) Bu yerin eleman türünü (13)'te s[0] ile belirleyecekler ama önce türün olası const, immutable, veya shared belirteçlerinden kurtulmak istiyorlar. std.traits.Unqual, türün saf halini verir (unqualified).
(13) typeof(s[0]), ilk elemanın türünü verir; (12)'de gördüğümüz gibi Unqual bunun saf halini üretir.
(14) Yeni dizinin uzunluğu n * s.length olacak; zaten bütün amaç bu :)
(15) Tekrarlanacak olan dizinin uzunluğu tek olduğunda, sonuç dizinin bütün elemanlarını bu tek değere eşitliyoruz. Sol taraftaki 'r[]' kullanımına dikkat edin. Bu konu şurada "Bütün elemanlar üzerindeki işlemler" başlığında var:
http://ddili.org/ders/d/dilimler.html
(16) Sonuç diziyi parça parça asıl dizinin elemanlarına eşitliyoruz
(17) r'nin türü artık const, immutable, veya shared taşımadığı için sonucun türünü tekrar döndürmek istediğimiz asıl dizi yapıyoruz.
Alıntı:
> Bu arada array.d modülünde iki tane replicate() metodu var ama benim program bu metoda gidiyor nereden biliyoruz! gdb öğrendik ya :)
İki replicate işlev şablonunun şablon kısıtlamaları farklı (aşağıda S, tekrar edilecek aralığı ifade ediyor):
- birisi "S bir dinamik dizi ise" durumuna uyuyor:
if (isDynamicArray!S)
isDynamicArray D.ershane'de geçmiyormuş; std.traits'te buldum.
- diğeri ise "S bir giriş aralığıysa (yani bir InputRange ise) ama dinamik dizi değilse" durumuna uyuyor:
if (isInputRange!S && !isDynamicArray!S)
Şablon kısıtlamaları şu bölümde "Şablon kısıtlamaları" başlığı altında geçiyor:
http://ddili.org/ders/d/sablonlar_ayrintili.html
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]