Forum: Ders Arası RSS
D.ershane opEquals eşitlik karşılaştırması
erdem (Moderatör) #1
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: D.ershane opEquals eşitlik karşılaştırması
Şans eseri TDLP'da da aynı konuyu okuyordum. Dershane'de aynı yerdeyim :)

import std.string, std.stdio;
 
class Saat {
    int saat;
    int dakika;
    int saniye;
 
    override bool opEquals(Object o) const {
        auto sağdaki = cast(const Saat) o;
 
        return((saat == sağdaki.saat)
               &&
               (dakika == sağdaki.dakika)
               &&
               (saniye == sağdaki.saniye));
    }
    
        
    override string toString() const {
        return format("%02s:%02s:%02s", saat, dakika, saniye);
    }
    
    this(int saat, int dakika, int saniye = 0) {
        this.saat   = saat;
        this.dakika = dakika;
        this.saniye = saniye;
    }
}
 
class ÇalarSaat : Saat {
    int alarmSaati;
    int alarmDakikası;
 
    override bool opEquals(Object o) const {
        auto sağdaki = cast(const ÇalarSaat)o;
        return((super == o)
               &&
               (alarmSaati == sağdaki.alarmSaati)
               &&
               (alarmDakikası == sağdaki.alarmDakikası));
    }
    
    override string toString() const {
        return format("%s ♫%02s:%02s", super.toString(),
                      alarmSaati, alarmDakikası);
    }
    
    this(int saat, int dakika, int saniye,
         int alarmSaati, int alarmDakikası) {
        super(saat, dakika, saniye);
        this.alarmSaati    = alarmSaati;
        this.alarmDakikası = alarmDakikası;
    }
}
 
void main() {
    auto değişken0 = new Saat(6, 7, 8);
    auto değişken1 = new ÇalarSaat(6, 7, 8, 1, 2);
       
    assert((değişken0 == değişken0)
           &&
           (değişken0 == değişken1)
           &&
           (değişken1 == değişken0));
}

Bu programı çalıştırdığımda segmentation fault hatası veriyor.

assert kullanımını özellikle bu şekilde yazdım. Çünkü TDLP'de el sıkışma gibi bir kavramdan bahsediyordu. Yani x = y ise y = x olmalı hatta kendisiyle x = x şeklinde bile karşılaştırmış. Hatta örneğin iki referans null ise true döndürüyor. Yani bir nesneye bağlanmamış referansla da karşılaştırma yapıyor.

Ama tüm bunları opEquals'ın gerçek gerçeklemesini anlatırken yapıyor. Programcı bu işlevleri kendisi yazarken de bu assert'lerin geçerli olmasını bekler miyiz?
erdem (Moderatör) #2
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Tam olarak bu şekilde yapıyor sanırım:
bool eşitMi(Object soldaki, Object sağdaki) {
    // eğer aynı nesneyi gösteriyor ya da her ikisi null (bağlanmamış) ise
    // => eşit
    if(soldaki is sağdaki) return true;
    // eğer ikisinden biri null ise => eşit değil
    if(soldaki is null || sağdaki is null) { return false; }
    // eğer ikisi de aynı türe sahipse => eşitMi'yi bir kere çağırmak
    // yeterli
    if(typeid(soldaki) == typeid(sağdaki)) return soldaki.opEquals(sağdaki);
    // son durum el sıkışma :)
    return soldaki.opEquals(sağdaki) && sağdaki.opEquals(soldaki);
}
Bu şekilde kendi yazdığımız karşılaştırmalar için de bunları yazmamıza gerek var mı acaba. Çünkü override ile eskisini geçersiz hale getirmiş olduk.

Yalnız burada belirli kısımları kaldırmamız gerekiyor galiba..

Ben de tam burada konunun yarısında kalmışım :)
erdem (Moderatör) #3
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Örneğin ilk örnekte şu şekilde iki çalarsaati karşılaştırmak isteyince de hata veriyordu:

    auto değişken0 = new ÇalarSaat(6, 7, 8, 1, 4);
    auto değişken1 = new ÇalarSaat(6, 7, 8, 1, 2);
       
    assert(değişken0 != değişken1);

Saat ve ÇalarSaat'in karşılaştırma işlevlerini bu şekilde değiştirince yukarıdaki kod çalışıyor.

class Saat {
 
// ...
 
    override bool opEquals(Object sağdaki) const {
 
        // Diğer eleman bir Saat olmalı
        auto şu = cast(Saat) sağdaki;
        if (!şu) return false;
        return ((saat == şu.saat)
                &&
                (dakika == şu.dakika)
                &&
                (saniye == şu.saniye));
    }
}
 
class ÇalarSaat : Saat {
 
// ...
    override bool opEquals(Object sağdaki) const {
        // Diğer eleman bir ÇalarSaat olmalı
        auto şu = cast(ÇalarSaat) sağdaki;
        if (!şu) return false;
        return super.opEquals(şu) && alarmSaati == şu.alarmSaati
            && alarmDakikası == şu.alarmDakikası;
    }
}

Ama anladığım kadarıyla ÇalarSaat'in gözünden bakınca bir Saat kendisine eşit değil. Saat'in gözünden bakınca ve yukarıdaki tür dönüştürme işlemi ÇalarSaat'in Saat kısmını döndürdüğü için eşit olabiliyor.
acehreli (Moderatör) #4
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ı
İyi yakalamışsın! Bu da ben yazmaya başladıktan sonra değişen konulardan birisiydi. Gösterdiğin işlev src/druntime/src/object_.d dosyasında Object sınıfının içinde tanımlı:

    equals_t opEquals(Object lhs, Object rhs)
    {
        if (lhs is rhs)
            return true;
        if (lhs is null || rhs is null)
            return false;
        if (typeid(lhs) == typeid(rhs))
            return lhs.opEquals(rhs);
        return lhs.opEquals(rhs) &&
               rhs.opEquals(lhs);
    }

Ali
erdem (Moderatör) #5
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yalnız bu şekil sağdan soldan eşit karşılaştırmayı bu yüzden yazamıyoruz anladığım kadarıyla. Çünkü ÇalarSaat'in gözünde her zaman eşit değil çıkıyor.

Sizin yazdığınız kod da tam ayrıntılı incelemedim ama hemen hemen aynı gibi. Tek fark burada sağdaki geçerli bir nesneyi göstermiyorsa (null'sa) ya da dinamik türü Saat değilse false döndürüyor. Ama ortada null bir referans göremiyorum :)

Baktıktan sonra sorun sadece ÇalarSaat'in opEquals işlevinde
super.opEquals(o)
yerine
(super == o)
kullanılmasından kaynaklanıyor. Aslında bunlar eşit değil miydi :)
Bu mesaj erdem tarafından değiştirildi; zaman: 2011-05-02, 14:14.
Avatar
mert #6
Üye Ara 2010 tarihinden beri · 194 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ama anladığım kadarıyla ÇalarSaat'in gözünden bakınca bir Saat kendisine eşit değil. Saat'in gözünden bakınca ve yukarıdaki tür dönüştürme işlemi ÇalarSaat'in Saat kısmını döndürdüğü için eşit olabiliyor.
Erdem dünden beri opEquals işlevinde tam da bu noktada takılmış kalmıştım. Neden böyle olduğuna dair senin ulaştığın sonuca da bir türlü ulaşamadığımı belirtmem gerek. Ancak senin açıklamalarından sonra "Segmentation fault" (ayrıştırma hatası mı diyeceğiz?) hatasını giderebiliyorum.
Şimdi bu durumda nesnelerin her ikisi de ÇalarSaat nesnesi ve değerleri eşit. Ancak programımız nesnelerimizin çıktı sonucunda eşit olmadıklarını bildiriyor. Ama taşıdıkları değerler yönünden her ikisi de eşitler. Yani opEquals işleviyle bu sonuca varmamız gerekiyor.
Yalnız bu şekil sağdan soldan eşit karşılaştırmayı bu yüzden yazamıyoruz anladığım kadarıyla. Çünkü ÇalarSaat'in gözünde her zaman eşit değil çıkıyor.
O halde opEquals işlevi ile karşılaştırma yapamayacağız demek mi oluyor bu?

Kodlarımın tamamını aşağıya ekliyorum
.
import std.stdio;
import std.string;
 
class Saat
{
    int saat;
    int dakika;
    int saniye;
    
    this(int saat, int dakika, int saniye)
    {
        this.saat   = saat;
        this.dakika = dakika;
        this.saniye = saniye;
    }
    
    override string toString() const
    {
        return format("%02s:%02s:%02s", saat, dakika,saniye);
    }
    /*override bool opEquals(Object o) const
    {
        auto sağdaki = cast(const Saat)o;
        
        return(( saat == sağdaki.saat) && (dakika == sağdaki.dakika) && 
                         (saniye == sağdaki.saniye));
        
    }*/
    override bool opEquals(Object o) const 
    {
        /// diğer eleman da saat olmalı
        auto sağdaki = cast(const Saat) o;
        if (!sağdaki) {
            return false;
        }
        return (( saat == sağdaki.saat) && (dakika == sağdaki.dakika) 
                         && (saniye == sağdaki.saniye));
    }
}
 
class ÇalarSaat : Saat
{
    int alarmSaati;
    int alarmDakikası;
    
    this(int saat, int dakika, int saniye, int alarmSaati, int alarmDakikası)
    {
        super(saat, dakika, saniye);
        this.alarmSaati   = alarmSaati;
        this.alarmDakikası= alarmDakikası;
    }
    override string toString() const
    {
        return format("%s ♫%02s:%02s", super.toString(), alarmSaati, alarmDakikası);
    }
    
    /*override bool opEquals(Object n) const
    {
        auto sağdaki = cast(const ÇalarSaat)n;
        return( (super.opEquals(n)) && (alarmSaati == sağdaki.alarmSaati) 
                && (alarmDakikası == sağdaki.alarmDakikası) );
    }*/
    override bool opEquals(Object o) const
    {
        /// diğer eleman da ÇalarSaat olmalı
        auto sağdaki = cast(ÇalarSaat)o;
        if (!sağdaki) {
            return false;
        }
        return ((super.opEquals(sağdaki)) && (alarmSaati == sağdaki.alarmSaati) 
                && (alarmDakikası == sağdaki.alarmDakikası));
    }
}
 
 
void main()
{
    auto değişken1 = new Saat(6, 7, 8);    // çalışıyor
    auto değişken2 = new Saat(6, 7, 8);
    //assert(değişken1 != değişken2);
    if (değişken1 == değişken2) {        // veya
        writeln("Taşıdıkları değer yönünden eşitler");
    } else { 
        writeln("Eşit değiller");
    }
    auto ortak1 = new Saat(9, 10, 11);     // çalışıyor
    auto ortak2 = ortak1;
    //assert(ortak1 == ortak2);  
    if (ortak1 == ortak2) {         // veya
        writeln("Eşitler");
    } else {
        writeln("Eşit değiller");
    }
    
    auto masaSaati1 = new ÇalarSaat(17, 15, 5, 20, 30); // son işlevde hata verdi
    auto masaSaati2 = new ÇalarSaat(17, 16, 5, 20, 30);
    assert(masaSaati1 == masaSaati2); // assertion 
    if (masaSaati1 == masaSaati2) {
        writeln("masaSaati değişkenleri eşit");
    } else {
        writeln("masaSaati değişkenleri eşit değil")// eşit olmaları gerekmiyor mu?
    }
}
mert
Avatar
mert #7
Üye Ara 2010 tarihinden beri · 194 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Düzeltme:     
auto masaSaati1 = new ÇalarSaat(17, 15, 5, 20, 30); // son işlevde hata verdi
auto masaSaati2 = new ÇalarSaat(17, 15, 5, 20, 30);

dünkü didişmede masaSaati2 nesnesi eşitliğin olmayacağı durumda kalmış.
 auto masaSaati2 = new ÇalarSaat(17, 16, 5, 20, 30)

Şu an da eşitliği gösteriyor opEquals. Bir önceki mesajımı yok sayabilirsiniz
mert
erdem (Moderatör) #8
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #6
mert:
Ama anladığım kadarıyla ÇalarSaat'in gözünden bakınca bir Saat kendisine eşit değil. Saat'in gözünden bakınca ve yukarıdaki tür dönüştürme işlemi ÇalarSaat'in Saat kısmını döndürdüğü için eşit olabiliyor.
Erdem dünden beri opEquals işlevinde tam da bu noktada takılmış kalmıştım. Neden böyle olduğuna dair senin ulaştığın sonuca da bir türlü ulaşamadığımı belirtmem gerek. Ancak senin açıklamalarından sonra "Segmentation fault" (ayrıştırma hatası mı diyeceğiz?) hatasını giderebiliyorum.

Aradan uzun zaman geçince koda şöyle bir baktım  :-p  O hatanın nedeni basitçe Ali bey'in

super.opEquals(o)

yerine

(super == o)

kullanmış olması. Aslında Ali beyin yazdığı kodda sadece bu değişikliği yaparsan çalıştığını göreceksin :) Neden Ali beyin yazdığı gibi çalışmıyor ben de bilmiyorum. Çünkü bunlar teorik olarak aynı şey :)

Benim eklediğim sadece null bir referansla karşılaştırmak olmuştu. O da örneğin bir ÇalarSaat nesnesi ile null yani henüz hiç bir nesneyi göstermeyen bir refaransı karşılaştırdığımızda eşit değil vermesi gerekiyor.

Yalnız bu şekil sağdan soldan eşit karşılaştırmayı bu yüzden yazamıyoruz anladığım kadarıyla. Çünkü ÇalarSaat'in gözünde her zaman eşit değil çıkıyor.

Evet örneğin Çalarsaat'in eşitlik karşılaştırma bölümünde parametre olarak bir Saat gönderdiğimiz zaman onu Çalarsaat'e dönüştürmeye çalışıyoruz. Ama Saat'in örneğin alarmsaati gibi ek üyeleri olmadığı için bu eşit değil çıkacak. Ama Saat'e parametre olarak ÇalarSaat gönderdiğimizde tür dönüştürme ÇalarSaat aynı zamanda bir Saat olduğu için ÇalarSaat'in ek üyelerini atacak ve bir Saat döndürecek. Bu yüzden eşit çıkacak.

Orada Ali beyin gösterdiği /src/object_.d karşılaştırma işlevinin nasıl çalıştığını bilmekte de fayda var.Bu normal matematik kurallarına göre çalışıyor. Yani

x = y ise y = x

tir gibi. Kendi yazdığımız karşılaştırma işlevlerini de daha esnek yazmak isteriz. Çünkü bizim açımızdan iki çalar saat'in dakika saniye .. gibi değerleri eşitse bunlar eşittir.
acehreli (Moderatör) #9
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 #5
(Bunları Erdem'in gerçek son yazdığını görmeden yazmışım. :))

Erdem'in son sorusuna yanıt vermeyi unutmuşum. :(

erdem on 2011-05-02, 12:24:
Sizin yazdığınız kod da tam ayrıntılı incelemedim ama hemen hemen aynı gibi. Tek fark burada sağdaki geçerli bir nesneyi göstermiyorsa (null'sa) ya da dinamik türü Saat değilse false döndürüyor. Ama ortada null bir referans göremiyorum :)

Aslında ÇalarSaat.opEquals içindeyken sağdaki null oluyor. Çünkü sağ tarafta Saat kullanıyoruz. ÇalarSaat.opEquals onu ÇalarSaat'e dönüştürmeye çalışıyor. O dönüşüm null üretiyor, çünkü Saat bir ÇalarSaat değildir. (Tersi doğrudur.)

Ama buradaki hata o null yüzünden oluşmuyor, program yığıtı tükendiği için oluşuyor.

Baktıktan sonra sorun sadece ÇalarSaat'in opEquals işlevinde
super.opEquals(o)
yerine
(super == o)
kullanılmasından kaynaklanıyor. Aslında bunlar eşit değil miydi :)

'super == o' yazınca yukarıda da konuştuğumuz src/druntime/src/object_.d içindeki algoritma tekrar işletiliyor. Sonsuza kadar (yığıt tükenene kadar) takılıyoruz. Bunu görmek için ÇalarSaat.opEquals içinde writeln ile bir satır yazdırmak yetiyor. :)

Ali
erdem (Moderatör) #10
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
'super == o' yazınca yukarıda da konuştuğumuz src/druntime/src/object_.d içindeki algoritma tekrar işletiliyor.

Olay budur :) Mert senin de bu konuyu açman çok iyi olmuş.

Bir de TDPL'de günümüz dmd derleyicileri tarafından henüz desteklenmeyen kodlar bulunabiliyor.
Avatar
mert #11
Üye Ara 2010 tarihinden beri · 194 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Teşekkür ederim. Tdpl için henüz erken. Ancak notumu aldım. Buradaki açıklamalar oldukça aydınlatıcı. Ben daha Ali hocamın anlattıklarını bitiremedim ki, Sonra arkasından bütün forumun tartışılmış konuları var. Adım adım ilerliyorum. Anlamadıklarımı veya çelişkiye düştüğüm yerleri burada ilgili konu başlığında sizlere soruyorum.

Zaten sizlerin olabildiğince açık ifadeleriniz de konulara başka boyutlar, farklı bakış açıları ve derinlikler kazandırıyor.

Çalışmak da keyifli olabiliyor bu haliyle. Zihninize sağlık :-)
mert
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:
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-21, 19:21:21 (UTC -08:00)