Forum: Ders Arası RSS
Şablonlar ile yığın sınıfı
Sayfa:  önceki  1  2  3  4  sonraki 
acehreli (Moderatör) #31
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj ID 6591
zafer:
empty()'nin sadece bu gerçeklemede kullanılması gerektigini ve dışarıdan kontrolsüz erişime kapalı olması gerektigini düşünüyorum.

Eğer InputRange ise o üç işlevi sunmuş olması gerekir. İsteyen istediği gibi kullanabilmeli.

"Bu gerçeklemede kullanılması" derken nasıl bir kısıtlama düşünüyorsun? "empty()'yi çağırabilirsiniz ama hemen sonrasında front()'u da çağırmalısınız" gibi bir istek mantıklı değil.

Ayrıca empty()'nin kontrolsüz kullanılacağı da aklıma yatmıyor. Yaptığı tek şey boş olup olmadığını söylemek olduğu için zararlı da olamaz.

Ali
zafer #32
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
Eğer InputRange ise o üç işlevi sunmuş olması gerekir. İsteyen istediği gibi kullanabilmeli.

Ali aralıklar konusunu tam olarak bilmiyorum dolayısıyla yanlış düşünüyorda olabilirim. Baştan bunu belirttikten sonra şöyle devam edeyim. empty(), popFront() ve front() işlemlerinin amacının sınıfa aralık olarak çalışabilme olanagı sağladıgını düşünüyorum. İsteyen istedigi gibi kullansın derken örneğin birisi yanlışlıkla popFront()' u çagırıp aralıgı daraltma gibi bir durum olabilir mi?

Aslinda özet olarak benim anladıgım bu metotları hiçbir şekilde kısıtlama (private) işaretleme durumumuz yok. Bu doğru mu? Ben bir sınıf yazarı olarak bu metotları kendime saklama hakkına sahipmiyim? Biraz bencil miyim yoksa :)
https://github.com/zafer06 - depo
acehreli (Moderatör) #33
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
zafer:
birisi yanlışlıkla popFront()' u çagırıp aralıgı daraltma gibi bir durum olabilir mi?

Eğer bu türü bir aralık olarak ilan etmişsek yanlış da kullanılabilir çünkü söylediğin başka her işlev için de geçerli. Herkes her işlevi yanlışlıkla çağırabilir.

Ben bir sınıf yazarı olarak bu metotları kendime saklama hakkına sahipmiyim?

Türün kendisini aralık yapmak yerine bir yan tür tanımlayabilir ve bu türü kendi modülünde tanımlayabilirsin. Tam eşdeğeri olmasa da aşağıdaki sayfada "ÖğrenciAralığı" geçen paragrafta bunun bir benzerini uyguluyorum:

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

Ali
Avatar
Salih Dinçer #34
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Bence önce aralıklar için özelleşmiş şu malum üç işlevi, D.ershane'den referansla hatırlayalım...

Aşağıda foreach'in for() işleviyle ifade edilmiş hali bulunuyor ve Ali hocam şurada konuyu çok güzel açıklamış; alıntılayım:

    for ( ; /* bitmediği sürece */; /* başından daralt */) {

        auto eleman = /* aralığın başındaki */;

        // ... ifadeler ...
    }

foreach'in kendi türlerimizle de çalışabilmesi için yukarıdaki üç özel bölümde kullanılacak olan üç özel üye işlev tanımlamak gerekir. Bu üç işlev; döngünün sonunu belirlemek, sonrakine geçmek (aralığı baş tarafından daraltmak), ve en baştakine erişim sağlamak için kullanılır.

Bu üç üye işlevin isimleri sırasıyla empty, popFront, ve front'tur. Derleyicinin arka planda ürettiği kod bu üye işlevleri kullanır:
    for ( ; !aralık.empty(); aralık.popFront()) {
 
        auto eleman = aralık.front();
 
        // ... ifadeler ...
    }
Görüleceği üzere bir döngü olma şartıyla biz bu işlevleri farklı şekillerde kullanabiliriz. Sanırım benim önceki sayfalarda while kullanmam da kuralı bozmuyor? Hatta retro() işlevini kullanmadan şu şekilde de tersini alabilirdik:
void main() {
    auto birAralık = Aralık(3, 7);
 
    foreach (eleman; birAralık) eleman.write("\t");
    writeln;    // Düzden aralığı ekrana yansıttık...
 
    for ( ; !birAralık.empty(); birAralık.popBack()) {
 
        auto eleman = birAralık.back();
 
        eleman.write("\t");
    }
    writeln;    // Tersten aralığı ekrana yansıttık...
}
 
struct Aralık {
    :    :    :    // Tabi ek olarak aşağıdakileri de eklediğimizi farzetmeli...
    void popBack() {
        --son;
    }
    int back() const {
        return son - 1;
    }
}
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2012-07-09, 14:46.
zafer #35
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #33
acehreli:
Herkes her işlevi yanlışlıkla çağırabilir.

Herkes her değişkeni yanlışlıkla değiştirebilir. Bunun için değişkenlerimizi immutable ile koruma altını alıyoruz.

Sınıfların ne olup olmadıgı ile ilgili anlatılan yazılırda bazen cd-rom örneği ile karşılaşırız. Burada cd-rom bir sınıfa benzetilir, cd-rom cd okuma işlevini gerçekleştiren kapalı bir kutudur. Dış dünyaya ise sadece kutunun kapağını açıp kapatabileceğimiz bir özelligini açmıştır. Bu sayede cd-rom kapalı kutu içinde tutarlı bir şekilde çalışmakta ve üreticinin öngöremediği dış etkilerden korunmaktadır. Kullanıcı içini açıp kurcalayabilir ama o zaman garanti dışı kalacagını kabul etmiş olur ;)

Salih Dinçer:
Sanırım benim önceki sayfalarda while kullanmam da kuralı bozmuyor?

Salih sorun senin while ile kullanman degil. Biz yukarıda bahsettigim cd-rom cihazına ses cd'lerini okuma özelligi ekliyoruz ama gel bu sefer kapağı kapatma imkanımız olmuyor. Kapağı açık bir şekilde satışa sunuyoruz. Yada kapağı kapatıyoruz ama bu sefer aynı özelliği sağlamak için yanında küçük bir kutu ile satışı çıkarmak zorunda kalıyoruz. :)

Benim anladığım olay bu şekilde yanlış anladıysam affola. Neticede bana göre aralık entegrasyonu sınıfta bir erişim zafiyeti yaratıyor ve bence bu önemli bir detay. Tabi diğer taraftan sizin aklınızdan geçen benimde aklımdan geçiyor. Bizden çok daha bilgili olan insanlar bu durumu düşünmedi mi? Oturup konuşmak anlamak gerek tabi ;)
https://github.com/zafer06 - depo
acehreli (Moderatör) #36
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
zafer:
Neticede bana göre aralık entegrasyonu sınıfta bir erişim zafiyeti yaratıyor ve bence bu önemli bir detay.

Kesinlikle hayır. Çünkü bunun aralıklarla değil, üyelere erişimle ilgisi var.

Ama bazı türler neredeyse bütünüyle erişim sağlamak için vardırlar. Herhalde bir dilimin elemanlarına erişebilmek de yanlış kabul edilmez:

    dilim[indeks] = 42;    // cd'nin kutusunu deldik! 

Ama hayır, hiç de kutuyu delmiyoruz çünkü o erişim bile opIndex()'ten (ve arkadaşlarından) geçiyor. Zaten dilim o yüzden yanlış indeks ile erişimleri yakalayabiliyor.

Aynısı aralıklar için de geçerli: Bütün erişim işlevler yoluyla sağlandığı için ne kadar erişim sunduğu aralığın kendisine bağlı. Eğer erişim sağlaması gerekmeyen bir türse zaten aralık arayüzü vermemeli.

Daha önce söylediğin gibi, kendi iç işleri için aralıklardan yararlanabilir ve bunu dışarıya açmayabilir.

Ali
zafer #37
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
Kesinlikle hayır. Çünkü bunun aralıklarla değil, üyelere erişimle ilgisi var.

Kesinlikle evet. Çünku empty(), popFront(), front() üye metotları temelde sınıfın aralık işlemlerini gerçekleştirmek için varlar. Aksi takdirde bu metotlar sınıfta tanımlanmayacağı için herhangi bir erişim sorunuda yaşanmayacaktır.

Sorunu doğru ortaya koymak gerkir. Bana göde aralıklar "Sınıf üyelerine erişimi kısıtlama" ilkesini bozduğu için bir sıkıntı yaratır. Bu çok önemli mi bilmiyorum, aslında bu dışarıyı kapatılamayan bu metotların içerisinde ne olduğu ile ilgili, örnegin empty() metodu için böyle bir sıkıntıdan söz etmek pek doğru olmaz. Neticede bunu konuşmak gerekir belki mantıklı ve kabul edilebilir bir açıklamasıda olabilir. Ancak bu şekilde bir yaklaşımla degil tabi :)

acehreli:
Herhalde bir dilimin elemanlarına erişebilmek de yanlış kabul edilmez:

Ali konuyu saptırıyorsun. Sende biliyorsun ki dilim ve sınıf farklı yapılar ama eğer sen bunları aynı kefeye koyup yorum yapıyorsan, sana diyecek birşeyim yok. Bana sadece haklısın demek kalıyor, istedigin buysa.

    dilim[indeks] = 42;    // cd'nin kutusunu deldik! 

Yukarıdada belirttim eğer sen kutuyu bilinçli olarak açıyorsan bu durumda cihazın garanti dışı kaldığınıda kabul etmiş olursun. Buna yapabilecek bir şey yok zaten, benim anlatmak istedigim kasıtlı olmayan durumlardı. Tıpkı hiç kimsenin bilinçli olarak hatalı kod yazmayacagı gibi ;)
https://github.com/zafer06 - depo
Bu mesaj zafer tarafından değiştirildi; zaman: 2012-07-10, 02:14.
Kadir Can #38
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Eğer gerçekten ihtiyaç varsa aklıma şöyle bir çözüm geliyor;
Şimdi biz aralıkları, bazı işlevleri kullanabilmek için oluşturuyoruz.Eğer aralık işlevlerini uygun şekilde sarma uygularsak ve aralık işlevlerinden gerekenlerini kendi sınıfımız içinde gerçeklersek sorun kalmaz gibi geliyor. Örneğin empty, front ve popFront() bize bir InputRange sunar. foreach() kullanmamız gereken yerde tekTekEriştir() gibi bir işlev tanımlarsak ve foreach()'ı o işlev içinde sunarsak, empty, front ve popFront()'u private ile işaretleyebiliriz. Bu sayede dışarıdan erişime kapanmış olurlar.Tabi gereken her işlev için bir tanımlama yaparsak biraz uzun olabilir.
Bunun dışında eğer çok önemli verilerle çalışıyorsak ben her zaman yedekli çalışılması gerektiğini düşünüyorum. Mesela programın iki çalışması arasında yedek dosyalar(İşimize göre veritabanı vb.) oluşturursak yapılan hataları geri alma şansımız olabilir.
acehreli (Moderatör) #39
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #37
zafer:
bu metotlar sınıfta tanımlanmayacağı için herhangi bir erişim sorunuda yaşanmayacaktır.

Benim söylediğim her şey sınıfın sunduğu elemanlara erişimin gerekli olduğu varsayımına dayanıyor. Yani erişim gerekmişse aralık olarak kodlayabiliriz, erişim gerekmemişse aralık olarak kodlamayabiliriz.

Sen genelde aralıkların sarmayı deldiğini söylüyorsun. Ben buna katılmıyorum çünkü tanım gereği, aralık kullanılmışsa zaten elimizde bir topluluk vardır.

Sorunu doğru ortaya koymak gerkir. Bana göde aralıklar "Sınıf üyelerine erişimi kısıtlama" ilkesini bozduğu için bir sıkıntı yaratır.

Kabul: Eğer erişimi kısıtlanacak bir sınıfsa tabii ki aralıklarla erişim sunulmaz. Tekrar etmek gerekirse, bunun aralıklarla ilgisi yok; sunulmaması gereken erişimi sunmakla ilgisi var.

acehreli:
Herhalde bir dilimin elemanlarına erişebilmek de yanlış kabul edilmez:

Ali konuyu saptırıyorsun. Sende biliyorsun ki dilim ve sınıf farklı yapılar

Aynı D dilimleri gibi işleyen bir sınıf yazıldığını düşünelim. Yani tek amacı dizi elemanlarına kontrollü erişim sağlamak olsun. (Zaten D dilimlerinin Phobos türleri olacakları konusunda planlar vardı.)

Bu durumda dilimlerle bu sınıf arasında fark var mıdır? Yok ise, dilimlerde çok yararlı olan aralık arayüzü onunla aynı biçimde işleyen sınıf için zararlı mıdır?

Tek söylediğim, aralıkların kategori olarak sarmayla ilgili sorunları bulunmuyor.

    dilim[indeks] = 42;    // cd'nin kutusunu deldik! 

Yukarıdada belirttim eğer sen kutuyu bilinçli olarak açıyorsan bu durumda cihazın garanti dışı kaldığınıda kabul etmiş olursun. Buna yapabilecek bir şey yok zaten, benim anlatmak istedigim kasıtlı olmayan durumlardı. Tıpkı hiç kimsenin bilinçli olarak hatalı kod yazmayacagı gibi ;)

Tabii ki. Dilim örneğine geri dönelim. Programcıyı kendisinden korumak için elemanlarına yazma erişimi sağlamadığımızı düşünelim. Yararlı mı olur?

Hmmm belki de sen elemanların veya topluluğun değişebilirliğinin zararlarını ortaya atıyorsun. Eğer eleman değiştirme veya popFront() olmasa hatalar da azalır. Fonksiyonel diller seninle aynı fikirdeler. :)

Ali
Avatar
Salih Dinçer #40
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #38
Kadir Can:
Eğer gerçekten ihtiyaç varsa aklıma şöyle bir çözüm geliyor;
Şimdi biz aralıkları, bazı işlevleri kullanabilmek için oluşturuyoruz.Eğer aralık işlevlerini uygun şekilde sarma uygularsak ve aralık işlevlerinden gerekenlerini kendi sınıfımız içinde gerçeklersek sorun kalmaz gibi geliyor.
Aşağıdaki gibi bir şey mi, Kadir? Bir nevi garanti belgesi ve/veya etiketiyle taşıdığımız bir CD-ROM driver oldu, değil mi? Belki Zafer'in ihtiyacına çözüm olur...
import std.stdio;
 
void main() {
    with(new Taşıyıcı (0, 10)) {
        foreach(i; Düzden) i.write("\t");
        writeln;
    }
 
    with(new Taşıyıcı (0, 10)) {
        foreach(i; Tersten) i.write("\t");
        writeln;
    }
}
 
class Taşıyıcı {
    private int[] veri;
    int başlangıç, bitiş;
    
    this (int baş, int bit) {
        başlangıç = baş;
        bitiş = bit;
    }
    ~this() {
        veri = veri[0..0]; // .init çalışmıyor ne hikmetse...
        // Error: null has no effect in expression (null)   
    }
    private struct Aralık {
        int baş;
        int son;
 
        this(int baş, int son) {
            this.baş = baş;
            this.son = son;
        }
        bool empty() const {
            return baş == son;
        }
        void popFront() {
            ++baş;
        }       
        void popBack() {
            --son;
        }
        int back() const {
            return son - 1;
        }
        int front() const {
            return baş;
        }
    }
    
    auto Düzden() {
        with(Aralık(başlangıç, bitiş)) {
            for ( ; !empty(); popFront()) {
                veri ~= front();
            }
        }
        return veri;
    }
    auto Tersten() {
        with(Aralık(başlangıç, bitiş)) {
            for ( ; !empty(); popBack()) {
                veri ~= back();
            }
        }
        return veri;
    }
}
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #41
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bence güzel. front()'lar ref döndürmedikleri için içerideki elemanların değiştirilmelerine de izin vermiyorlar.

~this() içindeki işlemlere hiç gerek olmasa da şu ikisi de derleniyor:

        veri = (int[]).init;
        veri = veri.init;

Ali
zafer #42
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Arkadaşlar iyi niyetiniz için çok teşekkürler ama sanırım benim kendimi ifade etme sorunum var.

Böyle bir çözümü zaten Ali ilk mesajında belirtmişti. Benim anlatmak istedigim bir fikir bir düşünceydi. Yani sınıfın doğası geregi metotoları erişim belirteci ile kısıtlamak varken neden kulağı tersten tutuyoruz sorusunun cevabını arıyordum.

Bu şartlar altında konuyu devam ettirmenin kendi adıma bir anlamı kalmadığını düşünüyor ve bu konuya katkı sağlayan tüm sevgili arkadaşlarıma çoook teşekkür ediyorum. :)
https://github.com/zafer06 - depo
Kadir Can #43
Üye Haz 2010 tarihinden beri · 413 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Evet Salih, bahsettiğim tam olarak o şekildeydi. :)
Avatar
Salih Dinçer #44
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj ID 6489
Şimdi ilgili dersi işlerken, Zafer'in başlattığı bu başlıktan çok faydalandım, teşekkürler Zafer.

Bir kaç ekleme yapmak ve soru sormak istiyorum...
zafer on 2012-07-04, 06:48:
Ben opApply içindeki if kontolünden kurtulmak için kodu şöyle düzenlemeye çalıştım. Birde siz bakın nasıl olmuş, bir eksik veya hata var mı? Ne dersiniz ?
    int opApply(int delegate(ref T) islemler)
    {
        int sonuc;
        for(int i = konum; i >= 0; --i)
        {
            sonuc = islemler(yigin[i]);
        }
        return sonuc;
    }
Öncelikle yukarıdaki şekilde değişebilen "konum" değeriyle döngüyü başlatmak soruna sebep oluyor. Çünkü siz herhangi bir anda Pop() üye işlevini çağırdığınızda doğal olarak değişken de değişiyor...:)

acehreli on 2012-07-04, 10:39:
opApply() içinde islemler()'in döndürdüğü değere bakmayı unutuyorsunuz. O değer sıfırdan farklı ise bizim kullanıcımız kendi foreach döngüsü içindeyken 'break' demiş demektir. Ona saygı göstermeli ve sonuç sıfırdan farklı olduğunda biz de opApply()'dan çıkmalıyız.
Ayrıca if() sorgusunu kaldırmayı ben de sevdim. Ancak yukarda Ali hocamın bahsettiği şeyi anlayabilmiş değilim. Kaldırmamalı mıydık? Peki bahsedilen break anı hangi döngü tarafından yapılıyor?

Bu arada anlayabilmek için sınıfı baştan yazdım. Anlamlarındaki derinliği sevdiğim için yine push() ve fetch() üye işlevlerini kullandım. Tabi, yarısında Türkçe ifadeler (konum, bellek vb.) kullanmak çok hoşuma gitmiyor. Oldum mu tam Türkçe veya İngilizce olsun istiyorum! Ama araya imzamız olsun diye Türkçe isimler koymak, hiç de fena değil...:)
class Yığın (T){
    private:
        size_t konum;
        T[] bellek;
    
    this (size_t kapasite) {
        bellek.length = kapasite;
    }
    
    public:
    void push(T)(T veri) {
        bellek[konum++] = veri;
        //konum++;  // Eğer önce artarsa bellek[0] kullanım dışı kalır!
    }
     
    T fetch() {
        //konum--;  // Her manada önce konum eksilmesi gerekli...:)
        return bellek[--konum];
    }
    
    void rewind() {
        konum = bellek.length;
    }
    
    bool empty() {
        return konum == 0;
    }
    
    //* code-toggle-on/off
    void popFront() {
        --konum;
    }
    
    T front() const {
        return bellek[konum - 1]// -1: Range'i, fetch ile uyumlu yapıyor!
    }/*/
    int opApply(int delegate(ref T) uygula) {
        int index;
        for(int i = bellek.length - 1; i >= 0; --i)
        {
            index = uygula(bellek[i]);
        }
        return index;
    }//*/
}
/*(Not: Denemek için her iki kodu kopyalarken aradaki bu yazılanları çıkarmayı ihmal edebilirsiniz!)
Bu sınıf üzerinde aşağıdaki denemeleri yaptım. Son deneme çıktısını altında verdim. Bu bize rewind() işlevinin neden lazım olabileceğini gösteriyor. Aynı sorun for() ile erişimlerde de göze çarpıyor! Ancak opApply() kullandığınızda, konum değişkeni devre dışı bırakıldığı için böyle bir sorun olmuyor. Bu sefer de take() kullanamıyorsunuz...:(
*/
import std.stdio;
 
void main() {
    immutable başla = 65;   // A harfi ile başlar
    immutable sınır = 26;   // Z harfi ile biter
    /*
    with(new Yığın!char(sınır)) {
        write("Kuruldu!");
        sınır.write("\n\t^---Yüklenen veri adeti / türü--->", typeid(bellek));
        
        for(char i = başla; i < (başla + sınır) ; i++) push(i);
        // A'dan Z'ye harfler yığına yollandı...
        writeln(" yığın içeriği:");
        
        do fetch.write("  "); while(!empty);
        rewind();   // Bunu yapmadığımızda alt satır hata verir!
        writeln("\n");
        fetch.writeln("<--Taşma durumunda hata verebilir...\n");
    }//*/
    auto harf = new Yığın!char(sınır);
    for(char i = başla; i < (başla + sınır); i++)
    {
        harf.push(i);
    }
    foreach(c; std.range.take(harf, 10)) c.write("  ");
    writeln;  // Tersten ilk 10 veri istendi...
    
    //harf.rewind(); // Bu olmazsa sonraki döngü baştan başlamaz!
    
    foreach(c; harf) c.write("  ");
    writeln;  // Bellekteki tüm veri istendi...   
} /* Çıktısı:
Z  Y  X  W  V  U  T  S  R  Q  
P  O  N  M  L  K  J  I  H  G  F  E  D  C  B  A  
*/
İşte böyle...:)

Güzel şeyler bunlar, Zafer dahil katılım sağlarsa çok sevinirim...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #45
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
bahsedilen break anı hangi döngü tarafından yapılıyor?

Eğer dışarıdaki foreach döngüsü bir 'break' ile kırılmışsa islemler() sıfırdan farklı bir değer döndürür. O değere bakmalıyız ve sıfırdan farklı olduğu zaman opApply() içindeki döngüyü de kırmalıyız.

Daha kolay görülsün diye daha da küçük bir yapı tanımladım. main()'deki kullanıcı kodları foreach'i erkenden kırmak istiyor (görülen ilk tek sayıda 'break' ile çıkıyor):

import std.stdio;
 
void main()
{
    auto dizi = SayıDizisi(0,5);
 
    foreach (sayı; dizi) {
        writeln(sayı);
        if (sayı % 2) {
            break// <--- Kullanıcı döngüyü ilk tek sayıda kırmak istiyor
        }
    }
}
 
struct SayıDizisi
{
    int baş;
    int son;
 
    this(int baş, int son)
    {
        this.baş = baş;
        this.son = son;
    }
 
    int opApply(int delegate(int sayı) işlem) const
    {
        /*
         * Üzerinde konuşurken dışarıdaki foreach ile karışmasın diye bunu for
         * ile gerçekleştirmeye karar verdim. Burada foreach de olabilirdi:
         *
         *   foreach (sayı; baş .. son) {
         *       işlem(sayı);
         *   }
         */
        for (int sayı = baş; sayı != son; ++sayı) {
            işlem(sayı)// <--- Bu opApply'ın break'ten haberi yok
        }
 
        return 0;
    }
}

Çıktıdan anlaşıldığına göre döngü kırılmamış:

0
1
2
3
4


Bunun nedeni, derleyicinin main()'deki döngüyü tam olarak şuna dönüştürmesidir:

    dizi.opApply(
        (int sayı) {
            writeln(sayı);
            if (sayı % 2) {
                return 1// "break ile çıkıldı" anlamında
            }
 
            return 0// "normal olarak sonlandı" anlamında
        }
    );

(O kodu main()'deki bütün foreach'in yerine yazabilirsiniz. Çıktı aynı olacak.)

Görüldüğü gibi, derleyici "kullanıcı break ile çıkmak istiyor" bilgisini, temsilciden sıfırdan farklı bir değer döndürerek veriyor. İşte opApply() içindeki döngüdeyken o değere bakmamız gerekir. Asıl kodu şöyle değiştiriyorum:

    int opApply(int delegate(int sayı) işlem) const
    {
        for (int sayı = baş; sayı != son; ++sayı) {
            immutable break_mi = işlem(sayı);
 
            if (break_mi) {
                return break_mi;
            }
        }
 
        return 0;
    }

(Not: break_mi'nin türü aslında int olsa da bir bool değişken gibi adlandırdım. dönüşDeğeri vs. de olabilirdi.)

Artık döngü ilk tek sayıda kırılır:

0
1


rewind() işlevinin neden lazım olabileceğini gösteriyor.

İşte o daha önce konuştuğumuz topluluk-aralık karşılaştırmasına bağlı. Aralık işlevleri doğrudan topluluk üzerinde olursa topluluktan istemeden eleman çıkartılır. Basit bir writeln() çağrısı bile topluluğu boşaltabiliyor.

O yüzden her topluluk elemanları üzerinde ilerlemeyi sağlayan bir aralık türü sunmalı ve ilerlendikçe bu aralık daralmalı; asıl topluluk korunmalı.

Bunu dilimlerde görüyoruz; popFront() ile dilim eleman kaybeder ama eriştirdiği elemanlar kendi dizilerinde durmaya devam ederler.

Ek olarak, eğer aralığın kendisi daha sonradan kullanılabilmek üzere saklanabiliyorsa o zaman save() işlevini sunar. save() elemanları kopyalamaz, aralığın durumunu saklar.

Bütün bunlara rağmen ben daha önceki bir gözlemime döneceğim: Yığın veri yapısı üzerinde eleman kaybetmeden ilerlemek zaten doğal gelmiyor çünkü ilerleme kavramı bütünüyle baştaki elemanı çıkartma kavramı üzerine kurulu. Ama yukarıda da gösterildiği gibi, bu yapının nasıl gerçekleştirildiğini (dilim kullanıyor) bilen bir yan aralık tanımlanabilir ve o aralık bütün elemanlar üzerinde ilerleyebilir. Ne olursa olsun bu bana doğal gelmiyor.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Sayfa:  önceki  1  2  3  4  sonraki 
Forum: Ders Arası RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-22, 05:02:55 (UTC -08:00)