Forum: D Programlama Dili RSS
Kullanıcının tanımladığı tür nitelikleri (UDA)
acehreli (Moderatör) #1
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ı
Konu adı: Kullanıcının tanımladığı tür nitelikleri (UDA)
dmd 2.061 yeni bir olanak getirdi: User Defined Attributes (UDA).

UDA'ları başka dillerden bilen programcılar çok sevindiler. :) Benim hiç deneyimim yok. Şimdilik D forumlarından ve şu taslaktan öğrenilebiliyor:

  https://dl.dropbox.com/u/18386187/attribute.html#uda

Bu olanak şunları getiriyor:

  • Türlere (ve değişkenlere) kullanıcının tanımladığı nitelikler vermek. Bu nitelikler @property söz dizimiyle örneğin @ÖzelNitelik diye yazılıyor.

  • Bu nitelikleri derleme zamanında sorgulamak ve duruma göre kod yazmak.

İkinci maddeden anlaşılacağı gibi UDA bütünüyle derleme zamanında işleyen bir olanak. Birden fazla nitelik verilebiliyor. Nitelikler çokuzlu olarak elde ediliyorlar.

Aşağıdaki program @GüvenleKopyalanabilir diye bir nitelik tanımlıyor, onu Yapı isimli türe veriyor (ama BaşkaYapı'ya vermiyor):
import std.stdio;
 
/* Başka türleri ve nesneleri nitelendirirken kullanacağımız bir tür
 * tanımlıyoruz. Bu türün üye değişkenleri de olabilir ama bu türün isminin
 * yeterli olduğunu düşünüyorum. (Ek olarak, bu konuda daha önce hiç deneyimim
 * de yok. :p)
 *
 * Adından anlaşıldığı gibi, bu niteliği güvenle kopyalanabilen türleri
 * nitelemek için kullanacağız.
 */
struct GüvenleKopyalanabilir
{}
 
/* Bu, yukarıdaki niteliğe sahip olan bir tür. Aşağıdaki ilk satırın tek
 * yaptığı, Yapı'nın GüvenleKopyalanabilir niteliğine sahip olduğunu
 * belirlemek.
 *
 * Nitelikler aşağıda görüldüğü gibi __traits(getAttributes) ile elde
 * edilebiliyorlar.
 */
@GüvenleKopyalanabilir
struct Yapı
{}
 
/* Bu yapını GüvenleKopyalanabilir niteliği bulunmuyor.
 */
struct BaşkaYapı
{}
 
/* Bu şablonun bu konuyla doğrudan ilgisi yok ve hatta bunun Phobos'ta zaten
 * olmasını beklerim. (Fazla aramadım; belki de vardır).
 *
 * Tek yaptığı, türün belirtilen niteliğe sahip olup olmadığını belirlemek.
 */
template niteliğiVar_mı(T, SorgulananNitelik)
{
    /* Bu, yalnızca bu şablon tarafından kullanılan bir yerel işlev. */
    bool var_mı()
    {
        /* Kullanıcının tanımladığı nitelikler __traits(getAttributes) ile
         * öğreniliyor. Bu kodun yaptığı, türün nitelikleri üzerinde ilerlemek
         * ve aranan niteliğe rastlanırsa true döndürmek.
         */
        foreach (t; __traits(getAttributes, T)) {
            if (typeid(t) is typeid(SorgulananNitelik)) {
                return true;
            }
        }
 
        return false;
    }
 
    enum niteliğiVar_mı = var_mı();
}
 
/* Bu, kullanıcının yazmış olduğu bir işlev. Nitelik vermenin ve onları
 * sorgulamanın yararını gösteriyor.
 */
void foo(T)(T parametre)
{
    /* Şablonlar gibi, nitelikler de bütünüyle derleme zamanında işleyen bir
     * olanak. 'static if'ten ve yukarıda tanımladığımız 'niteliğiVar_mı'dan
     * yararlanarak T'nin niteliğini sorguluyoruz ve foo() işlevini buna uygun
     * olarak tanımlıyoruz.
     */
    static if (niteliğiVar_mı!(T, GüvenleKopyalanabilir)) {
        writefln("'%s' güvenle kopyalanabilirmiş. Kopyalıyorum.", T.stringof);
        T kopyası = parametre;
        /* ... algoritmanın gerisi ... */
 
    } else {
        writefln("'%s' kopyalanamıyormuş. Başka bir algoritma kullanıyorum.",
                 T.stringof);
        // ... kopyasını almayan başka algoritma ...
    }
}
 
void main()
{
    auto y = Yapı();
    foo(y);
 
    auto by = BaşkaYapı();
    foo(by);
}
foo() işlevi main içinde iki farklı türle kullanılıyor. Bu türlerden birisi @GüvenleKopyalanabilir niteliğine sahip olduğu için foo()'nun gerçekleştirimi onun için farklı oluyor:

'Yapı' güvenle kopyalanabilirmiş. Kopyalıyorum.
'BaşkaYapı' kopyalanamıyormuş. Başka bir algoritma kullanıyorum.


Ben yukarıda 'struct GüvenleKopyalanabilir {}' diye tanımlanmış olan başlı başına bir tür kullandım. Önerilen o... Buna rağmen, belki de daha kolay oldukları için temel türlerden olan değerler bile nitelik olabiliyorlar. Aşağıdaki program bunu gösteriyor. Ek olarak, birden fazla nitelik de verilebiliyor:
import std.stdio;
 
/* Bu yapının nitelikleri sıradan iki değer. */
@(42, "merhaba")
struct Yapı
{}
 
void foo(T)(T nesne)
{
    /* Nitelikler çokuzlu olarak elde ediliyorlar. */
    enum nitelikler = __traits(getAttributes, T);//
 
    /* İspatlayalım: */
    static assert(__traits(getAttributes, T)[0] == 42);
    static assert(__traits(getAttributes, T)[1] == "merhaba");
}
 
void main()
{
    Yapı a = Yapı();
    foo(a);
}
Ali
Avatar
zekeriyadurmus #2
Kullanıcı başlığı: Talha Zekeriya Durmuş
Üye Eki 2012 tarihinden beri · 701 mesaj · Konum: Samsun/Türkiye
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Açıkçası nerede kullanabilirim diye çok düşündüm ama aklıma bir türlü gelmedi ama kullanışlı işe yarar birşey olduğuna eminim. Ama aklıma takılan birşey oldu

@(42, "merhaba")
şeklinde değilde

@(a = 42, b = "merhaba")
şeklinde bir kullanım var mı? veya bu paralel bir kullanım çünkü ilk değer ile ikinci değerin sıraları farklı olabilir direk 0.indeks olarak bulmak yerine "b".index olarak bulmak daha mantıklı olabilir.

Zekeriya
Bilgi meraktan gelir...
acehreli (Moderatör) #3
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ı
zekeriyadurmus:
@(a = 42, b = "merhaba")
şeklinde bir kullanım var mı?

Bildiğim kadarıyla yok.

ilk değer ile ikinci değerin sıraları farklı olabilir direk 0.indeks olarak bulmak yerine

Haklısın. Ben de öylesine bir örnek olarak yazmıştım. Yoksa şu değerde niteliği var mı demek de mümkün. Aşağıdaki örnek foo() içinde T'nin her iki niteliğinin olup olmamasına bağlı olarak farklı oluşturuluyor.
import std.stdio;
 
bool niteliğiVar_mı(T, D)(D değer)
{
    foreach (t; __traits(getAttributes, T)) {
        static if (is (typeof(t) == D)) {
            if (t == değer) {
                return true;
            }
        }
    }
 
    return false;
}
 
/* Bu yapının nitelikleri sıradan iki değer. */
@(42, "merhaba")
struct Yapı
{}
 
void foo(T)(T nesne)
{
    static if (niteliğiVar_mı!T(42) &&
               niteliğiVar_mı!T("merhaba")) {
        writeln("Var");
 
    } else {
        writeln("Yok");
    }
}
 
void main()
{
    Yapı a = Yapı();
    foo(a);
}
Hiçbir örnekte farklı kodlar yazmadım ama 'static if' ve 'else' bloklarının bambaşka kodlar içerebilecekleri de açık herhalde.

Ali
Avatar
Salih Dinçer #4
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #1
Merhaba,

Ben de kodlarda çok fazla değişiklik yapmadan anlayabilmek için ve biraz da basitleştirerek (belki karmaşıklaştırdım!), bir örnek yaptım:
import std.stdio;
 
void main() {
    Yapı[] data;
           data ~= Yapı(1);
           data ~= data[$-1].mümkünseYedekle();
    
    data[0].i = 0;
    data.writeln;
 
    BaşkaYapı[] test;
                test ~= BaşkaYapı(1);
                test ~= test[$-1].mümkünseYedekle();
    
    test[0].i = 0;
    test.writeln;
}/* Çıktısı:
'Yapı' KOPYALANIYOR...
[Yapı(0), Yapı(1)]
'BaşkaYapı' KOPYALANAMADI !
[BaşkaYapı(0), BaşkaYapı(0)]
*/
Ali hocanın örneğinin başındakileri fazla değiştirmeden sadece anlamı kuvvetlendirmek için şu şekilde düzenledim:
enum GüvenleKopyalanabilir;
 
@GüvenleKopyalanabilir struct Yapı {
    int i;
}
 
struct BaşkaYapı {
    int i;
}
 
template niteliğiVar_mı(T, SorgulananNitelik) {
    bool var_mı() {
        foreach (t; __traits(getAttributes, T)) {
            if (typeid(t) is typeid(SorgulananNitelik)) {
                return true;
            }
        }
        return false;
    }
    enum niteliğiVar_mı = var_mı();
}
 
T mümkünseYedekle(T)(T tür) {
    T kopyası; // İlklenmiş türün kopyası
 
    static if(niteliğiVar_mı!(T, GüvenleKopyalanabilir)) {
        writefln("'%s' KOPYALANIYOR...", T.stringof);
        kopyası = tür; // Kopyalanan türle ilkleniyor...
    } else {
        writefln("'%s' KOPYALANAMADI !", T.stringof);
    }
    return kopyası; // Boş veya kopya türü döndürüyor...
}
acehreli:
Ben yukarıda 'struct GüvenleKopyalanabilir {}' diye tanımlanmış olan başlı başına bir tür kullandım. Önerilen o...
Bence yukarıdaki gibi enum kullanmak daha hoş, ne dersiniz?

Başarılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #5
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hoşmuş, bir de şöyle yaptım:
enum GüvenleKopyalanabilir;
 
@GüvenleKopyalanabilir {
    struct Yapı {
        int i;
    }
 
    struct BaşkaYapı {
        int i;
    }
}
'Yapı' KOPYALANIYOR...
[Yapı(0), Yapı(1)]
'BaşkaYapı' KOPYALANIYOR...
[BaşkaYapı(0), BaşkaYapı(1)]

Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
zekeriyadurmus #6
Kullanıcı başlığı: Talha Zekeriya Durmuş
Üye Eki 2012 tarihinden beri · 701 mesaj · Konum: Samsun/Türkiye
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #3
Bir foreach döngüsüne sokarak yapılabilir evet benim kafamdaki biraz daha farklıydı

bool özellikVarmı = "ozellik1" in __traits(getAttributes, T) && __traits(getAttributes, T)["ozellik1"] = "silinebilir";

tarzında foreach kullanmadan yapılabilse güzel olurdu :)

Verdiğiniz örnekleri inceleyince konuyu biraz daha iyi anladım :)

Zekeriya
Bilgi meraktan gelir...
acehreli (Moderatör) #7
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 #4
Salih Dinçer:
Bence yukarıdaki gibi enum kullanmak daha hoş, ne dersiniz?

Şimdilik bana da öyle geliyor. Bir yapı kullanılsa üye değişkenleri ve üye işlevleri de olabiliyor ama onların gerekip gerekmeyeceklerini bilmiyorum.

Ali
Mengu (Moderatör) #8
Kullanıcı başlığı: NONSERVIAM
Üye Tem 2009 tarihinden beri · 347 mesaj · Konum: Dersaadet
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
bunun karsiligi java'da annotation. kaynaga ve kaynak icindeki her seye bir metadata atamak. diyelim bir User sinifiniz var, bu sinifta da hangisi ozelligin primary key oldugunu belirlemek istiyorsunuz yada User sinifinin tablo ismini belirlemek istiyorsunuz otomatik olusturulmasi yerine.

@TableName("my_users") // tablo adini belirle
class User {
 
    @PrimaryKey // bu attr primary key
    @Unique       // ayrica unique
    long id;
 
}

ne isimize yaradi?

veritabani icin tablolari olustururken bu sinifa herhangi bir metadata atanmis mi diye baktik. atandiysa kullanilmak istenen verileri kullandik.
http://www.mengu.net - some kind of monster
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ı
Mengu:
    @PrimaryKey // bu attr primary key

Çok daha anlamlı bir örnek! :)

Biz de tam şu sıralarda primary key kavramını kullanan bir tasarım üzerinde çalışıyoruz. Bizimki C++ ve kod üretimine dayanıyor. Sınıf kendimiz yazmıyoruz; sınıfları bizim tarifimizden (schema) yola çıkan bir program üretiyor. O tarifte bizim de primary key'imiz var. Şimdi düşünüyorum da, D dilini kullanmış olsak belki de kod üretmemize gerek de kalmayacaktı çünkü D'nin kod üretme yetenekleri de üstün. (Ama bu konuyu fazla düşünmedim. D olsa belki yine de programla kod üretirdik; bilmiyorum.)

Neden D kullanmadığımızın tartışmasına girmeyelim. Deneyimli bir sürü C ve C++ programcısı var. Onların hepsinin birden aklını çelmek kolay değil. :)

Ali
Avatar
Salih Dinçer #10
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #8
Peki bu java kodunda @PrimaryKey'in özel bir anlamı mı var? Yoksa ayrı bir yerde kod yazıp bunu sorgulatıyor musunuz?

Ali hocam herhalde şablonlardan bahsediyorsunuz? Bu arada konu dışı ama şurada yazdığımız paragraflar bile aslında bir "code" değil mi! Yani PC'de gördüğümüz renkler dahil her şey bir kodlamanın ürünü ki tam olarak vurgulamak istediğim için yazıyorum. Örneğin bu satırları okurken de HMTL etiketlerin 'dürt'üğü kodlar sayesinde okumayı gerçekleştiriyoruz. Bütünde kod olmasa da ayrıntıya girdikçe kod öbeklerine boğuluyoruz. Düşünün henüz kullanıcı tarafındayız...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #11
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:
Ali hocam herhalde şablonlardan bahsediyorsunuz?

Hayır, kendi yazdığımız bir program kendi tarif dosyamızı okuyup C++ kodu üretiyor. Atıyorum:

// Tarif
sinif: Foo
    uye: int isim
    uye: int numara   primary_key


Sonuçta oluşan kaynak kod:
// C++ kodu
class Foo
{
    int isim_;
    int numara_
 
public:
 
    int anahtar() const {
        // iste primary_key kavramini bunu yazmak icin kullandik
        return numara_;
    }
 
    int isim() const {
        return isim_;
    }
 
    int numara() const {
        return numara_;
    }
 
    // ... yazıcı ve okuyucu işlevler, vs. ...
};

Ali
Avatar
Salih Dinçer #12
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hocam bir nevi dizi kurulumu gibi (-bknz. aşağıdaki örnek) standart bir işin açık bir şekilde ifade edilmesini istediğinize göre çok kapsamlı ve karışık bir proje olmalı. Ama hala primekey ifadesini anlayabilmiş değilim?
/* int array[10] = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
 * yerine:
 */
int array[10];
void arrayinit() {
  array[0] = 9;
  array[1] = 8;
  array[2] = 7;
  // and so on until array[9]
}
Ali hocamın cevabı için teşekkür eder Mengu'nun cevabını beklemeye devam ederim...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #13
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:
hala primekey ifadesini anlayabilmiş değilim

Birbirine benzeyen çok sayıda sınıf olacağından hepsini elle yazmak yerine "// Tarih" diye belirttiğim dosyada tarif ediyoruz ve C++ (ve Python) kodlarını otomatik olarak üretiyoruz.

primary_key, bu sınıfın nesnelerinin birbirlerinden nasıl ayırt edileceklerini belirliyor. Veritabanına kaydederken hangi üyesini indekslemek için kullanacağız gibi...

Aynı mantık UDA'lerde de kullanılabilir. Bir şablon yazıyoruz ve bize T diye bir tür geliyor. O türün hangi üyesinin örneğin @AnaAnahtar diye nitelendirilmiş olduğuna bakıyoruz ve işlemimizde onu kullanıyoruz... gibi... Gerçek deneyimim olmadığı için tam bir örnek veremiyorum. (Ama Mengü verdi zaten. :D )

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:
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-19, 04:11:37 (UTC -08:00)