Thread overview
Meta kodlama üzerine bir soru
Mar 19, 2023
Salih Dincer
Mar 19, 2023
Salih Dincer
Mar 19, 2023
Ali Çehreli
March 19, 2023

Emin değilim, belki bir cevap olacak!

Eğer bu yazdıklarımı okuyorsanız cevabı henüz tam bulamamış veya anlayamamış olmalıyım. Zaten bulursam büyük ihtimalle göndermemiş olacağım, yani aşağıdakiler boşa kürek hani :)

Adım adım denemeliyim...

struct Uzun_isimli_ve_yazmak_zahmetli(T) { T i; }
alias Yeni(T) = Uzun_isimli_ve_yazmak_zahmetli!T;

Değerli Ali hocamdan en son bu yukardaki ilk örneği öğrenmiştim. Takmaadların parametre alabildiğini bilmiyordum. Bu gerçekten hayatı kolaylaştırıyor ve kullanımı basit, şu şekilde:

Yeni!int n;
assert(n.i == 0);

Eee bu da gayet basit, anlamayanı döverler :)

alias Unconst(T : const U, U) = U;

Kullanımına geçmeden, adeta bunun "Proto Template" olduğunu belirtmeliyim. Evet, bu terimi ben uydurdum çünkü bende yarattığı his bu ve gerçekten çok güzel, leziz:

alias cType = typeof(c);
Unconst!cType Int;
Int = 2;

Hayatı kolaylaştıran bir başka öğe: is ile typeof birleşimi. Evet, artık şablonlara girdik. Böyle bir şey zaten vardı da ben mi uydurdum onu bilmiyorum ama kullanıyorum:

alias isTypeOf = ito;
template ito(alias value)
{
  alias T = typeof(value);
  enum ito(U) = is(U == T);
}

Kullanmak için yakın markaja aldığım şablona (bir de kardeşi var allSatisfy) ihtiyacımız olabilir.

import std.meta : anySatisfy;
  static assert(!anySatisfy!(isTypeOf!Int, ubyte, uint, ulong));
  static assert(anySatisfy!(isTypeOf!Int, ubyte, int, ulong));

Yaptığı iş çok basit: İlk parametreyle sırasıyla sonraki parametreleri karşılaştırmak ve herhangi biri uyuşursa true döndürmek. Dikkat ederseniz önceki örneklerdeki const(c)'den türeyen Int'i kullandım. İlk assertdeki ünleme (!) dikkat edin. Karşılaştırılabilecek int olmadığına göre false döndü.

Eğer std.meta'yı incelerseniz runtime'deki bir şablona ulaşıyorsunuz kaynağı şu:

import core.internal.traits : anySatisfy;

// ve çekirdek kod bir foreach içinde:
template anySatisfy(alias F, A...)
{
  static foreach(T; A)
  {
    static if(!is(typeof(anySatisfy) == bool) && F!T)
    {
      enum anySatisfy = true;
    }
  }
  static if(!is(typeof(anySatisfy) == bool))
  {
    enum anySatisfy = false;
  }
}

Bu kadar yeter çünkü sıkıldım :)

Soruya gelip çıkıyorum, biz sadece bunu bir döngü ile halledemez miydik? Yani bize lazım olan, foreach içinde dönen bir static if is() değil mi? Tıpkı Ali hocanın staticMapN()'de kodladığı gibi akıllı bir şeyler olurdu sanki!

Bu işler bir yılan gibi bu kadar uzun ve karmaşık olmamalı :)

March 19, 2023

On Sunday, 19 March 2023 at 11:51:36 UTC, Salih Dincer wrote:

>

... sıkıldım :)

Soruya gelip çıkıyorum, biz sadece bunu bir döngü ile halledemez miydik? Yani bize lazım olan ...

:)

Biraz daha sabra ihtiyacım varmış çünkü "sıkıldım" demekle aslında önümdeki merdiven gibi dizilen kolaylığı göremedim. Zirveye çok yakınmışım, erken pes ettiğim için üzgünüm! İşte çözümüm:

template whichIn(alias value, A...) {
  alias T = typeof(value);
  static foreach(U; A) {
    static if(!is(typeof(whichIn) == bool)
            && is(U == T)
    ) enum whichIn = true;
  }
  static if(!is(typeof(whichIn) == bool))
    enum whichIn = false;
}

enum : byte { num = 123 }
pragma(msg, whichIn!(num, uint, int, ushort, byte)); // true

Lütfen öcekiyle birlikte iki kodu da karşılaştırınız. Çünkü anySatisfy()'daki F'e dikkat, meğer o bir alias'mış. Yani aslında biz ona alias func ismi de verebilirdik! Diğer şablonu kalbine gömerdik :)

Dip Not: && ile önceki sonuca bakmak akıllıca. Çünkü true yakalandığında bir daha 2. şarta bakılmaz. Çok temel mevzuyu burada görmekteyiz. Bu arada, şablonun ismi ne olsun? Sanırım which'li bir şey gider?

Başarılar...

March 19, 2023
On 3/19/23 06:02, Salih Dincer wrote:

> İşte çözümüm:

Güzel. :)

> ```d
> template whichIn(alias value, A...) {
>    alias T = typeof(value);
>    static foreach(U; A) {
>      static if(!is(typeof(whichIn) == bool)
>              && is(U == T)

Oradaki 'whichIn' neyi temsil ediyor? İçinde bulunduğumuz şablon ise bir türü yoktur çünkü bu şablonun neyi temsil ettiğinin kararını vermeye çalışıyoruz.

O parçayı çıkarınca da aynı çalıştığına göre orada bir gariplik var. ;)

     static if(is(U == T)
     ) enum whichIn = true;

Senin yazdığın gibi yazdım ama kendim her zaman için küme parantezlerini de kullanırdım:

     static if(is(U == T)) {
         enum whichIn = true;
     }

> şablonun ismi ne olsun? Sanırım which'li bir şey
> gider?

isOneOf, typeIsOneOf, ... (?)

Ali

May 24

Öncelikle başlığı hortlattığım için kusura bakmayın çünkü 1 sene ile son kullanma tarihi olmaz bu konu ölmez hep yaşar aslında :)

On Sunday, 19 March 2023 at 17:02:35 UTC, Ali Çehreli wrote:

> >

şablonun ismi ne olsun? Sanırım which'li bir şey
gider?

isOneOf, typeIsOneOf, ... (?)

Ali hocam hepsininin gideri var (Turkish Terminology)! Şaka bir yana neler var neler. Yeni bir örnek:

void convert(in bool[] range, out size_t[] list) {
  enum size = typeof(list[0]).sizeof * 8;/***
  import std.range.primitives : ElementType;
  enum size = ElementType!(list[]).sizeof * 8; //*/

  import std.range : chunks;
  foreach(bit64; range.chunks(size))
  {
   //..
  }
}

void main() {
  auto range = new bool[111];
  range[0..2] = [true, true];

  size_t list = [41, 42];
  range.convert(list);
}

Üç yıldıza geçmeden önce, bakınız burada yapılan in / out parametre operatorleri aynı anda kullanımı deneniyor. Aslında kullanmasanız da oluyor hani. Çünkü dizi alıyor ve bu işlev içine referans olarak aktarılıyor. Yani herhangi bir kopyasının alındığını söyleyemeyiz. Ama in'nin range'i değişmez yaptığını ve out'un da list'i ilkleyip perde arkasında ref'e çevirdiğini görebilirsiniz. Özellikle range'in tüketilmediği ve orijinalinin korunmasının istendiğin durumlarda yapıştırı ver-in :)

Gelelim meta programlama hususuna. Bilmem çok da konuyla alakalı mı ama benim burada vurgulamak istediğim eleman türünün (ElementType) çalışma zamanında tespit edilmesi hakkında. Çünkü chunks(size) ile kullanırken size'ı doğru tespit etmezsem (çünkü bazı işlemcilerde size_of 32 bit bir işaretsiz tür olabilir) işler karışabilir. Hatta std.range.primitives satır 1366'da derleme zamanında çalışan bir olanak var:

/**
The element type of `R`. `R` does not have to be a range. The
element type is determined as the type yielded by `r.front` for an
object `r` of type `R`. For example, `ElementType!(T[])` is
`T` if `T[]` isn't a narrow string; if it is, the element type is
`dchar`. If `R` doesn't have `front`, `ElementType!R` is
`void`.
 */
template ElementType(R)
{
    static if (is(typeof(R.init.front.init) T))
        alias ElementType = T;
    else
        alias ElementType = void;
}

Deneyebilmeniz için kod içine her iki olanağı da gömdüm. Elbette ElementType, meta programlama üzerine ve derleme zamanında çalışan bir olanak. Dolayısıyla bu işlev içinde çalışmayacağını göreceksiniz. O yüzden aradaki farkı iyi anlamanızı öneririm. Öte taraftan hiç eleman içermeyen bir dizi ilk elamanına nasıl eriştiği ve hata vermemesi de tam olarak bir muamma. Yani kod nedense çalışıyor hatta [41, 42] ile ilklemeden de deneyebilirsiniz. Ben out'un işlev görüp görmediğini anlamak için koymuştum.

Not: Ali hocam yaz aylarında tekrar buraya uğradığında lütfen typeof(list[0])'i nasıl hata vermeden yapabildiğimi açılasın ya da biri bana yazsın :)

SDB@79

May 29

On Friday, 24 May 2024 at 06:38:55 UTC, Salih Dincer wrote:

>

Not: Ali hocam yaz aylarında tekrar buraya uğradığında lütfen typeof(list[0])'i nasıl hata vermeden yapabildiğimi açılasın ya da biri bana yazsın :)

Uyuyan, hayalet foruma yazmaya devam :)

Sorumun cevabını şurada aldım:

https://forum.dlang.org/post/ymrwaopgxmdevnumnwmm@forum.dlang.org

Yani alışanın aksine 0. elemana erişmeye çalışmıyoruz. Neticede derlenirken ağacın bir yerinde tür eşleşiyor ve olduğu yere konuyor. Yöntemde büyük sıkıntı yok sanki?

SDB@79