Forum: Ders Arası RSS
Problem çözümleri eksik olan dersler
Sayfa:  önceki  1  2 
acehreli (Moderatör) #16
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 3885
erdem:
    Sayı[] sayılar = null;
    Sayı[] çiftler = null;
 
    auto sayı = new Sayı(0);
    sayılar ~= sayı;
    
    // referansı sayılar[0] da tutuyoruz
    assert(sayılar[0] is sayı);
 
    çiftler ~= sayı;
    assert((sayı is sayılar[0] && sayı is çiftler[0]));

Bu noktada tek nesne (new ile oluşturulmuştur ve isimsizdir) ve ona erişim sağlayan üç değişken var:


sayı ----------> nesne(0)
            |
sayılar[0]--|
            |
çiftler[0]--


 
    // burası biraz karışık gibi :(
    // şimdi yeni bir nesne oluşturduk ve ilk
    // referansımızı bu yeni nesneyi gösterecek şekilde değiştirdik
    // o zaman sayılar[0] ve çiftler[0]'da tutulan referansların
    // geçerli bir referans olduğunu söyleyebilirmiyiz
    
    sayı = new Sayı(1);

Şimdi sayı yeni bir nesneye erişim sağlıyor. Baştaki nesne hâlâ geçerli:


        --> nesne(1)
       |
sayı --      --> nesne(0)
            |
sayılar[0]--|
            |
çiftler[0]--


 
    
    swap(sayılar[0], çiftler[0]);
    // referansları yerdeğiştirsek bile her ikisi de aynı nesneyi
    // gösteriyor
    
    assert(sayılar !is çiftler); // bence bu çiftler sayıların dilimi değil
    assert(sayılar == çiftler)// ama içerikleri eşit şimdilik 
Benim buradan anladıklarım sayılar ve çiftler aslında nesneleri değil referansları tutuyor.

Doğru. Çünkü onlar Sayı dizileri. Sayı da bir class olduğu için zaten referanstır. Yani elimizde referans dizileri var.

Bana sanki gene çiftler sayılar'ın dilimi değil gibi geldi.

Yukarıdaki kodlarda öyle olmasını düşündürecek bir şey göremiyorum.

Bir de asıl önemli nokta sayı = new Sayı(1); dediğimizde sayılar[0] ve çiftler[0]'da kalan referansların geçerli bir referans olduklarını söyleyebilirmiyiz.

Evet.

Bana burdaki işlem şu örnekteki gibi geliyor.
 class A {
    int x = 42;
}
 
unittest {
    auto a1 = new A;
    assert(a1.x == 42);
    auto a2 = a1;       // yeni bir A nesnesi oluşturulmaz sadece A nesnesi
                        // a2 tarafından da gösterilmeye başlanır
    assert(a1 is a2);   
    assert(a1 == a2);
    
    a2.x = 100;
    assert(a1.x == 100);
}

Yani dolaylı olarak bir nesneyi gösteren iki referans oluşmasına izin verdik. Ama böyle bir durumda örnekteki gibi beklenmeyen  bir şekilde referans değiştiği zaman uygulamanın bir yerinde olan sürpriz değişiklikler diğer tarafına da yansıyabilir.

Kesinlikle. Sınıf nesnelerinin kopyalanmalarını istiyorsak dizilere de benzesin diye dup() isminde bir üye işlev yazmalıyız.

Ama uygulamada çoğunlukla D'nin (ve Java'nın) sınıflarının referans özellikleri gerekiyor. Ben C++ yazarken bile hemen hemen her sınıfı zaten D'deki gibi kullanıyorum:

// C++ kodu
 
// Sinifin tanimi; bu, D'deki "isimsiz nesne" gibi oluyor
class BirSinif {/* ... */};
 
// Referans türü; bu, D'deki "sınıf değişkeni" gibi oluyor
typedef boost::shared_ptr<BirSinif> BirSinifPtr;
 
// Nesne yapma işlev(ler)i; bu, D'deki new gibi oluyor
BirSinifPtr new_BirSinif(/* bir kurucusunun aldığı parametreler */)
{
    return BirSinifPtr(new BirSinif(/* bir kurucusunun aldığı parametreler */));
}
 
BirSinifPtr new_BirSinif(/* başka kurucusunun aldığı parametreler */)
{
    return BirSinifPtr(new BirSinif(/* başka kurucusunun aldığı parametreler */));
}

Ondan sonra program içinde hemen hemen her yerde BirSinifPtr'lar kullanıyoruz.

(Not: boost::shared_ptr yerine boost::intrusive_ptr daha hızlıdır ama ona geçmeyi gerektirecek bir durumla karşılaşmadık.)

Kısacası demek istediğim aslında aynı nesneyi gösteren birden fazla referans olmasına izin vermememiz gerekmiyor mu.

Duruma göre değişir. Kendi deneyimlerim doğrultusunda D'nin (ve Java'nın) seçtiği yöntemin çoğu duruma uygun olduğunu düşünüyorum.

Dediğim gibi bu örnek bana hem biraz karışık, hem de derste anlatılanları tam pekiştiremiyor gibi geldi  :huh:

O yüzden daha ilginç ve daha basit bir örnekle değiştirilmesini öneriyorum :)

Dikkate alınacaktır. :)

Ali
erdem (Moderatör) #17
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
erdem:
    Sayı[] sayılar = null;
    Sayı[] çiftler = null;
 
    auto sayı = new Sayı(0);
    sayılar ~= sayı;
    
    // referansı sayılar[0] da tutuyoruz
    assert(sayılar[0] is sayı);
 
    çiftler ~= sayı;
    assert((sayı is sayılar[0] && sayı is çiftler[0]));
    sayı = new Sayı(1);

Şimdi sayı yeni bir nesneye erişim sağlıyor. Baştaki nesne hâlâ geçerli:


        --> nesne(1)
       |
sayı --      --> nesne(0)
            |
sayılar[0]--|
            |
çiftler[0]--


Evet ben de tam olarak böyle düşünüyorum.

[Resim: http://i53.tinypic.com/11ae2z5.jpg]

acehreli:
Bana sanki gene çiftler sayılar'ın dilimi değil gibi geldi.

Yukarıdaki kodlarda öyle olmasını düşündürecek bir şey göremiyorum.

İki dizi arasında atama ya da bir kısmını gösterme gibi bir ilişki kurmamışız. O yüzden o iki dizi tamamen ayrı diziler olarak karşımıza çıkmaz mı :)
import std.stdio;
 
void main () {
 
    auto a = ["merhaba", "dünya"];
    string b[] = a;
    assert (a is b);            // a ve b aynı sınırlara sahip
    assert (a == b);
    
    b = a.dup;                  // şimdi kopyalıyoruz
    assert (a == b);            // konumları farklı da olsa a ve b eşit
    
    assert (a !is b);            // her ne kadar içerikleri eşit olsa da a
                                // ve b artık birbirinden farklı
    
}

Örneğin daha önceki mesajdaki
 assert(sayılar !is çiftler);
ifadesinin de içerikleri aynı olduğu için eğer dilim olsaydı is olmasını beklemezmiydik.   

acehreli:
Dikkate alınacaktır. :)

Aslında örneğin kendisinden çok neler olup bittiğini anlamak biraz karışık galiba :)

Teşekkürler ..
acehreli (Moderatör) #18
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ı
erdem:
acehreli:
Bana sanki gene çiftler sayılar'ın dilimi değil gibi geldi.

Yukarıdaki kodlarda öyle olmasını düşündürecek bir şey göremiyorum.

İki dizi arasında atama ya da bir kısmını gösterme gibi bir ilişki kurmamışız. O yüzden o iki dizi tamamen ayrı diziler olarak karşımıza çıkmaz mı :)

Açık olamamışım: kodlarda zaten sayılar ve çiftler'in dilim olduklarını düşündürecek bir şey olmadığını söylemek istedim.

Hmmm... Bugüne kadar kullandığım dilde eksiklikler olduğunu şimdi farkediyorum: Ben bir dilimin "başka dilimin erişim sağladığı elemanlara erişim sağladığını" söyleyince, bu doğal olarak yukarıdaki sayılar ve çiftler'e de uyuyor. Çünkü ikisinin de ilk elemanları aynı nesneye erişim sağlıyorlar. Bu açıdan bakınca birisi ötekinin dilimi gibi anlaşılabilir. Ama aslında farklılar; ilgisiz bir durum.

Dilim olabilmek için, başka bir dizinin veya dilimin erişim sağladıkları elemanların ardışık bir bölümüne erişim sağlamak gerekir. Elemanları teker teker atayarak aynı sonuca ulaşılması onları bu konuda ilişkilendirmez.

D dilimlerinin iki üyeleri olduğunu biliyoruz. Sözde bir tanımları şöyle olabilir:

struct __Dilim
{
    size_t length; // (aslında bu bir @property'dir)
    size_t ptr;
}

Şimdi başka bir dilimden ilklenen şu koda bakalım:

class Sınıf
{}
 
void main()
{
    Sınıf[] dilim0;
 
    foreach (i; 0 .. 4) {
        dilim0 ~= new Sınıf;
    }
 
    Sınıf[] dilim1 = dilim0[0..2];
 
    assert(dilim0.ptr == dilim1.ptr);
    assert(dilim0.length == 4);
    assert(dilim1.length == 2);
    assert(dilim0 !is dilim1);
    assert(dilim0 != dilim1);
}

Oradaki iki dilimin durumu şu:


                    nesne    nesne    nesne    nesne
                      ^        ^        ^        ^
                      |        |        |        |
                    ================================
                      o        o        o        o
                    ================================
                      ^
                      |
dilim0.ptr -----------|
dilim0.length == 4    |
                      |
dilim1.ptr -----------
dilim1.length == 2


Yani ikisi de bellekte yan yana duran elemanların başındakini gösteriyorlar. dilim1, bunlardan yalnızca ilk ikisinin yasal olduğunu düşünüyor. dilim0 da ilk dördünün... Bunun dışında bir şey bilmiyorlar.

Programı şimdi sayılar ve çiftler örneğine benzetmek için değiştiriyorum. Bu sefer sınıf değişkenlerini her iki dilime de ekleyeceğiz. Bu sefer ilk assert'ün de değiştiğine dikkat edin:

class Sınıf
{}
 
void main()
{
    Sınıf[] dilim0;
    Sınıf[] dilim1;
 
    foreach (i; 0 .. 4) {
        Sınıf değişken = new Sınıf;
        dilim0 ~= değişken;
 
        if (i < 2) {
            dilim1 ~= değişken;
        }
    }
 
    assert(dilim0.ptr != dilim1.ptr);   // <-- aynı değiller
    assert(dilim0.length == 4);
    assert(dilim1.length == 2);
    assert(dilim0 !is dilim1);
    assert(dilim0 != dilim1);
}

Şimdi durum şöyle:


dilim0.ptr -----------
dilim0.length == 4    |
                      v
                    ================================
                      o        o        o        o
                    ================================
                      |        |        |        |
                      v        v        v        v
                    nesne    nesne    nesne    nesne
                      ^        ^
                      |        |
                    ==============
                      o        o
                    ==============
                      ^
                      |
                      |
dilim1.ptr -----------
dilim1.length == 2


Sonuçta yine aynı nesnelere erişiliyor ama dilimlerde bulunan referanslar farklı.

Ali
acehreli (Moderatör) #19
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ı
acehreli:
Ben bir dilimin "başka dilimin erişim sağladığı elemanlara erişim sağladığını" söyleyince, bu doğal olarak yukarıdaki sayılar ve çiftler'e de uyuyor.

Kendimi yanıltmışım. O tanım aslında doğru. Bir sınıf değişkenini ilklediğimizde iki şey oluştuğunu hatırlayalım:

    Sınıf değişken = new Sınıf;

Soldaki değişken... Sağdaki ise nesne. Bence sınıf dizilerinin tanımında bir gariplik var:

    Sınıf[] dizi;

yazdığımız zaman, her ne kadar "sınıf dizisi" diyorsak da, aslında "sınıf değişkeni dizisi" demek daha doğru. Yukarıda çizdiğim şekillerde o ile belirlenenler sınıf değişkeni.

Bu açıdan bakınca, yani dilimlerin elemanlarının değişken olduklarını görünce, dilimin "aynı elemana erişim sağlaması" kavramı yine de geçerli. Çünkü elemanlar değişken, nesne değil.

Ali
erdem (Moderatör) #20
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #18
acehreli:
erdem:
acehreli:
Bana sanki gene çiftler sayılar'ın dilimi değil gibi geldi.

Yukarıdaki kodlarda öyle olmasını düşündürecek bir şey göremiyorum.

İki dizi arasında atama ya da bir kısmını gösterme gibi bir ilişki kurmamışız. O yüzden o iki dizi tamamen ayrı diziler olarak karşımıza çıkmaz mı :)

Hmmm... Bugüne kadar kullandığım dilde eksiklikler olduğunu şimdi farkediyorum: Ben bir dilimin "başka dilimin erişim sağladığı elemanlara erişim sağladığını" söyleyince, bu doğal olarak yukarıdaki sayılar ve çiftler'e de uyuyor. Çünkü ikisinin de ilk elemanları aynı nesneye erişim sağlıyorlar. Bu açıdan bakınca birisi ötekinin dilimi gibi anlaşılabilir. Ama aslında farklılar; ilgisiz bir durum.

Yok ben böyle anlamadım. Benim kasdettiğim daha önceki mesajlardaki
Burada çiftler sayıların dilimi.

ifadesiydi.

acehreli:
Dilim olabilmek için, başka bir dizinin veya dilimin erişim sağladıkları elemanların ardışık bir bölümüne erişim sağlamak gerekir. Elemanları teker teker atayarak aynı sonuca ulaşılması onları bu konuda ilişkilendirmez.

Aynen katılıyorum.

acehreli:
D dilimlerinin iki üyeleri olduğunu biliyoruz. Sözde bir tanımları şöyle olabilir:

struct __Dilim
{
    size_t length; // (aslında bu bir @property'dir)
    size_t ptr;
}

Bunun gerçeklemesini daha önce ben size sormuştum :)

Alttaki kodda da benim düşündüğümün aynısı. Tek farkla ki ilk örnekte ben dilim0'ın dizi olduğunu ve sadece dilim1'in dilim olduğunu düşünüyorum. İkinci örnekte ise bazı elemanları aynı nesneleri gösteren referanslar olsa da birbirinden tamamen bağımsız diziler olarak düşünüyorum. Bilmiyorum yanlış mı düşünüyorum.

Zaten sizin de belirttiğiniz gibi sayılar çiftler örneğinde ya da ikinci örnekte
     assert(sayılar.ptr != çiftler.ptr);
bir tanesinin diğerinin dilimi olabilmesi için yukarıdaki ifadesinin == olması gerekiyordu.

Ben şöyle düşünüyorum. Eğer iki tanesinin uzunluğu eşitse ve is koşulunu sağlıyorsa aynı sınırlara sahip.


Tüm bu konuştuklarımızdan nesneleri gösteren referansları sorunsuz bir şekilde dizilerde saklayabileceğimizi anlıyorum. İlk planda acaba bu referanslar geçersiz hale gelirse sonra çöp toplayıcı çalışıp belleği geri verebilir mi gibi değişik fikirler gelmişti. (İtiraf ediyorum bu nedenle bu soruyu sordum! :D )

Ama D de öyle serseri gösterge dangling pointer gibi durumlar oluşmadığı gibi referanslarda da problem olmuyor sanırım. Biraz da C++'nin sınıf yapısı ile D'nin ki sizin de bahsettiğiniz gibi farklı. Gene C++'de akıllı gösterge sınıfları ile normal sınıfların bellek yönetimini yapabiliyorduk.

Yanıtlar için çok teşekkürler! :)
acehreli (Moderatör) #21
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 2260
Asıl kod şöyleydi:

    Sayı[] sayılar;
    Sayı[] çiftler;
// ...
        sayılar ~= sayı;
// ...
            çiftler ~= sayı;

acehreli on 2010-06-23, 09:30:
canalpay:
Burada çiftler sayıların dilimi.

Doğru.

Erdem'in uyarısıyla kendimi (ve Can'ı) düzeltiyorum: çiftler sayıların dilimi değil.

Ali
acehreli (Moderatör) #22
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 #20
erdem:
Alttaki kodda da benim düşündüğümün aynısı. Tek farkla ki ilk örnekte ben dilim0'ın dizi olduğunu ve sadece dilim1'in dilim olduğunu düşünüyorum.

dilim0 da dilim, çünkü dinamik dizilerle dilimler aynı şey:

    int[] dilim0 = [ 11, 12, 13 ];
    int[] dilim1 = dilim0;

O kodda üç şey var:

- yan yana üç int
- onlara erişim sağlayan dilim0
- onlara erişim sağlayan dilim1

Yani dilim0 ile dilim1'in iç yapıları aynı.

(Sanıyorum sabit uzunluklu dizilerde durum farklı.)

Ben şöyle düşünüyorum. Eğer iki tanesinin uzunluğu eşitse ve is koşulunu sağlıyorsa aynı sınırlara sahip.

Zaten == işleci de o gerçekten yararlanır ve öncelikle ptr ve length'e bakar. Eğer onlar eşitse hiç eleman karşılaştırmasına geçmez.

çöp toplayıcı çalışıp belleği geri verebilir mi gibi değişik fikirler gelmişti

Nesneye erişim mümkün olduğu sürece çöp toplayıcı belleği geri almaz.

Ali
erdem (Moderatör) #23
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
dilim0 da dilim, çünkü dinamik dizilerle dilimler aynı şey:

    int[] dilim0 = [ 11, 12, 13 ];
    int[] dilim1 = dilim0;

O kodda üç şey var:

- yan yana üç int
- onlara erişim sağlayan dilim0
- onlara erişim sağlayan dilim1

Yani dilim0 ile dilim1'in iç yapıları aynı.

Çok haklısınız. Orada iki tane dizi nesnesi bir tane dizi var. Ben daha önce şeklini de çizmeme rağmen karıştırmışım  :huh:

[Resim: http://i53.tinypic.com/28u075e.jpg]

Bu arada umarım sizi fazla zorlamamışımdır :)
acehreli (Moderatör) #24
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 #22
acehreli:
(Sanıyorum sabit uzunluklu dizilerde durum farklı.)

Sabit uzunluklu diziler çok daha basit. Onlar C'deki diziler gibi, yalnızca yan yana elemanlardan oluşuyorlar:

import std.stdio;
 
void main()
{
    int[10] dizi;
 
    writeln("sizeof               : ", dizi.sizeof);
    writeln("length               : ", dizi.length);
    writeln("ptr                  : ", dizi.ptr);
    writeln("dizi adresi          : ", &dizi);
    writeln("ilk elemanının adresi: ", &dizi[0]);
}

Orada yan yana 10 elemandan başka bir şey yok. dizi, hepsini birden temsil ediyor. Dizinin ve ilk elemanının aynı adrese sahip olmaları bunu gösteriyor:

sizeof               : 40
length               : 10
ptr                  : FFD19848
dizi adresi          : FFD19848
ilk elemanının adresi: FFD19848


length bilgisi, hiç değişemediği için türün içinde mevcut; çünkü dizinin türü int[10]...

ptr diye bir üye de yok; herhalde dizinin adresi ile aynı şey...

Ali
erdem (Moderatör) #25
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
http://ddili.org/ders/d/tureme.html

Buradaki 2. çözümü gereksiz yere değiştirdim:

class Tren : DemirYoluAracı {
// ...
    this() {
        lokomotif = new Lokomotif;
 
        foreach (int i; 0 .. 5) {
            vagonlar.length = 5;
            vagonlar[i] = new Vagon;
        }        
    }
    
    override string ses() {
        string lokomotifSes = lokomotif.ses() ~ ' ';
        string vagonlarSes = replicate("~[tak tuk]", vagonlar.length);
        return lokomotifSes ~ vagonlarSes;
    }          
}
Böylece biraz da olsa görsel olarak arkada 5 vagon var havası oluşmuş oldu. Yakında bu trenler tren gelir hoşgelir♫ şarkısını da söylese şaşmamak lazım :)
acehreli (Moderatör) #26
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ı
Kendisi de DemirYoluAracı olan Tren başka DemirYoluAracı nesnelerini içerdiği için burada composite design pattern var.

Ali
erdem (Moderatör) #27
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Çok harika bir örnek olmuş. İnsanın bunu oyun haline getiresi geliyor  ;-)

Ayrıca Tren'in gene bir DemirYoluAracı olan vagon ve lokomotifleri içermesi dikkatimi çekmişti. Herhalde D kalıtımı bu şekilde gerçekliyor diye düşünmüştüm.
Bu mesaj erdem tarafından değiştirildi; zaman: 2011-05-02, 12:05.
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 
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-18, 17:26:24 (UTC -08:00)