Thread overview
char[] ve wchar[] OutputRange olamazlar
Feb 03, 2012
Salih Dinçer
Feb 03, 2012
zafer
February 03, 2012

Çok güzel bir analiz ve/veya hata bulma macerası...

Tıpkı "her şeyin bir açıklaması vardır" tespitine benziyor. Her ne kadar yazdığımız kodları kısa sürede unuttuğumuzda, böyle adeta filmi geriye sarmayı sıklıkla yapsak da burada izlenen yollar çok güzel örnek olmuşlar. Paragrafın başında bahsettiğim tespitin güzel bir uygulaması olmuş.

Teşekkürler...

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

February 02, 2012

Önceki bir konuda şu foruma gönderme yapmıştım:

http://dfeed.kimsufi.thecybershadow.net/discussion/thread/jgcfs5$2uss$1@digitalmars.com

Orada görüldüğü gibi, sabit uzunluklu dizgilere değer atamak için çeşitli yollar da denedim: copy, fill, insertInPlace, vs.

Onların hepsi aralık işlevleri olduklarından, ve dizgiler de std.array modülü eklendiği sürece aralık olduklarından, örneğin şu programın işleyeceğini umdum:

import std.algorithm;
import std.array;

void main()
{
   char[10] d;
   copy("merhaba", d);  // <-- derleme HATASI
}

Ne yazık ki derlenemiyor:

'Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) does not match any function template declaration
Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) cannot deduce template function from argument types !()(string,char[10LU])
'

Sorunu çözmek biraz zamanımı aldı. Çözümü ararken izlediğim yolun benzerini aşağıda gösteriyorum.

Hata mesajının içinde std.algorithm.copy şablonunun şablon kısıtlaması da görünüyor:

   if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1)))

Yani şu iki şartın sağlanması gerekiyormuş:

  • 'isInputRange!(Range1)'

  • 'isOutputRange!(Range2,ElementType!(Range1))'

isInputRange ve isOutputRange (İngilizce olsalar da adları üstünde), aralığın InputRange veya OutputRange olup olmadıklarını denetliyorlar. Şu bölümde tanıtılıyorlar:

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

Şablon parametresi olarak tür verilir ve o tür örneğin InputRange ise true döndürür. Deneyelim bakalım tanımında Range1'e karşılık gelen "merhaba" bir InputRange miymiş... InputRange tür istediği için "merhaba"yı değil, onun typeof ile elde ettiğimiz türünü vermeliyiz:

import std.stdio;
import std.range;

void main()
{
   writeln(isInputRange!(typeof("merhaba")));
}

O program 'true' yazdırıyor:

'true'

Güzel. Yani copy() şablonunun Range1 üzerindeki kısıtlamasını aşmış durumdayız. Şimdi diğer kısıtlamaya bakalım: Range2'nin, Range1'in elemanlarının türünü kabul eden bir OutputRange olması gerekiyormuş. Eğer o şart da sağlanıyorsa copy()'nin çağrılamaması için bir neden olmamalı.

Programımızda Range2 olarak 'd' isimli sabit uzunluklu dizgiyi kullanmıştık. Range1'in eleman türü olarak da herhalde immutable(char) doğru olur. Deneyelim:

   char[10] d;
   writeln(isOutputRange!(typeof(d), immutable(char)));

Ne yazık ki çıktısı 'false' oluyor! Değişebilen char ile deneyelim:

   char[10] d;
   writeln(isOutputRange!(typeof(d), char));

Yine 'false' oluyor!

Nasıl olur? Bu noktada şunu hatırlıyorum: Diziler OutputRange olarak kullanıldıklarında baş taraflarından kısalırlar. Çok saçma bir işlem gibi gelse de bunun mantıklı bir açıklaması var. Şu bölümde "Dizilerin OutputRange olarak kullanılmaları" başlığında anlatılıyor:

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

Şimdi daha iyi anlıyorum: OutputRange olarak kullanılan dizi başından kısaldığına göre sabit uzunluklu diziler OutputRange aralığı olamazlar! Çünkü sabit uzunlukludurlar, kısalamazlar!

Bu noktada uyanıyorum ve bir dilim kullanmayı akıl ediyorum: Asıl diziyi değil, bir dilimini OutputRange olarak kullanmak gerekir. Dilimler başlarından kısalabilirler ve o yüzden OutputRange olabilirler. Deneyelim:

   char[10] d;
   char[] dilim = d;
   writeln(isOutputRange!(typeof(dilim), char));

Yine olmuyor! Çıktısı yine 'false'. Hmmm? O zaman isOutputRange'i bir kenara bırakıp dilim'i kendim bir OutputRange gibi kullanmaya çalışayım. put() işlemi ile kullanılabilmesi gerekir. Bakalım:

   char[10] d;
   char[] dilim = d;
   put(dilim, 'X');

Yine hata!

'/usr/include/d/dmd/phobos/std/range.d(315): Error: static assert "Cannot put a char into a char[]"'

Nasıl yani? char[] içine char yerleştirilemez mi? range.d'nin o hatayı yazdıran 315 numaralı satırına bakınca sonunda olayı anlıyorum:

           static if (is(typeof(r.front = e, r.popFront())))
           {
               r.front = e;
               r.popFront();
           }
           else static if (isInputRange!E && is(typeof(put(r, e.front))))
           {
               for (; !e.empty; e.popFront()) put(r, e.front);
           }
           else
           {
               static assert(false,
                       "Cannot put a "~E.stringof~" into a "~R.stringof);
           }

Dikkat ederseniz aralığı (yani r'yi) hep .front ile kullanıyorlar. Zaten öyle olmasını da bekleriz: nasıl olsa aralık işlevleri bunlar... Yukarıdaki iki 'static if' deyimi başarısız olmalı ki 'else' bloğu işletilmiş ve hatayı görmüşüz. Şimdi bakalım dilim'in .front'unun türü neymiş:

   char[10] d;
   char[] dilim = d;
   writeln(typeof(dilim.front).stringof);

Çıktısı şaşırtıcı:

'dchar'

Nasıl? char dizisinin eleman türü nasıl dchar olur? Ha ha! :) Bu noktada kendi yazdığım bilgiyi tekrar hatırlıyorum. Şuradaki "std.array modülünün dizgilere özel yararı" başlığına bakın:

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

Çok ilginç ama çok yararlı biçimde, ne tür dizgi olursa olsun, aralık olarak kullanıldıklarında hepsinin eleman türü dchar'dır. Yukarıdaki bağlantıdaki bir sonraki başlık olan "Kendi elemanları bulunmayan aralıklar"a da bakın. Oradaki '"şu".front' örneği de güzel.

Aralıkların char[] ve wchar[] dizgileriyle neden kullanılamadıkları anlaşılıyor: .front'larının döndürdükleri dchar karakterleri kendilerine ait olamazlar! .front'larının döndürdüğü dchar karakterleri, her seferinde ya char'lardan ya da wchar'lardan üretilen geçici değerlerdir. (Aslında bir sağ değerdir (rvalue).) O dchar'a atama yapılamaz. O yüzden char[] gibi bir dilimi OutputRange olarak kullanamıyoruz.

Çok uzun yazdım ama aydınlandım. :)

Ali

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

February 03, 2012

Değişik ve keyifli bir yazı olmuş. İlgiyle okudum hatta çıktı aldım daha iyi irdelemek için.

Acaba diyorum şu webiner denen şeylerden bizde yapabilir miyiz? Bir kaç yerde rastladım çokta hoşuma gitti bir yazılımla konuyu anlatacak kişiye bağlanıp ekran görüntüsünü ve sesini alıyoruz ve sanki bir seminerde gibi onu dinliyoruz hatta soru sorup katılabilme imkanımızda oluyor. Bence çok güzel.

Bu konuyu canlı yayında :) dinlemeyi isterdim doğrusu.

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