Jump to page: 1 2
Thread overview
LookUp ve AA
Apr 12, 2023
Salih Dincer
Apr 13, 2023
Ali Çehreli
Apr 13, 2023
Salih Dincer
Apr 15, 2023
Ali Çehreli
Apr 18, 2023
Salih Dincer
May 03, 2023
Salih Dincer
May 03, 2023
Salih Dincer
May 03, 2023
Ali Çehreli
May 03, 2023
Salih Dincer
May 03, 2023
Ali Çehreli
May 03, 2023
Salih Dincer
April 12, 2023

Merhaba,

Daha önce hiç denememiştim, ta ki yabancı forumda şu iletiyle karşılaşıncaya kadar. Bildiğiniz ilişkisel (çağrışımsal) diziyi basit bir yapıyla sarmaladığınızda çok güçlü bir arkadaş çıkıyor:

struct LookUp(T)
{
  T*[string] data;

  auto set(string key, ref T value)
    => data[key] = &value;

  auto opIndex(string key)
    => key in data ? *data[key] : T.init;

  auto opSlice()
    => data.keys;
}

Aslında bu D'nin gücünü gösteriyor! Nasıl olur da bu dil yaygınlaşmaz diye hayıflanıyor insan. Buyrun şu aşağıdaki kodla deneyin ve gücü hissedin!

import std.stdio;

void main()
{
  struct S { string data; }
  
  auto foo = S("foo");
  auto bar = S("bar");

  LookUp!S table;
  
  table.set("foo", foo);
  assert(table["foo"] == foo);
  table["foo"].writeln;

  table.set("bar", bar);
  assert(table["bar"] == bar);
  table["bar"].writeln;

  table[].writeln;

  writeln([&foo, &bar]);
  table.writeln;
}

Dip Not: Bir de bunun karmaşığı, Voldemort tipi var ama şimdi çok fazla kafa karıştırmayayım dedim. Yoksa buraya nakledilmesi güç olan başka olaylar da var. Bence yukardaki de çok çok güzel. Haksız mıyım!

Başarılar...

April 13, 2023
On 4/12/23 15:28, Salih Dincer wrote:

>    auto set(string key, ref T value)
>      => data[key] = &value;

Parametre değerinin adresini saklamak çok riskli değil mi? Şöyle bir programla deneyelim:

import std;

void doldur(ref LookUp!int table) {
    foreach (i; 0 .. 10) {
        auto key = format!"key_%s"(i);
        writeln("key ", key, " i ", i);
        table.set(key, i);
    }
}

void main()
{
   LookUp!int table;
   doldur(table);
   writeln(table["key_9"]);
}

Çıktısı garip: :)

key key_0 i 0
key key_1 i 1
key key_2 i 2
key key_3 i 3
key key_4 i 4
key key_5 i 5
key key_6 i 6
key key_7 i 7
key key_8 i 8
key key_9 i 9
-1841429904

>    auto opIndex(string key)
>      => key in data ? *data[key] : T.init;

T.init döndürmek bazen kullanışlı olabilir ama ancak 'key'in geçersiz olduğunun önemi olmadığında çünkü böyle yapınca 'key' var da değeri mi T.init yoksa hiç mi yok bilemeyiz.

Ali

April 13, 2023

On Thursday, 13 April 2023 at 21:21:53 UTC, Ali Çehreli wrote:

>

Parametre değerinin adresini saklamak çok riskli değil mi?

Haklısınız hocam, özellikle yaptığım bir şey değil. Sadece soruyla uyumlu bir cevap içindi. Benzer durum Variant için de var mı?

Hocam mesela burada da "Range Violation" hatası almamak için Uninitialized VariantN döndürerek çözdüm:

mixin template LookUp2(string data = "")
{
  struct LookUp2Impl
  {
    import std.variant;

    private Variant[string] values;
    alias values this;

    @property {
      auto opDispatch(string key)() inout
      {
        Variant val;
        //assert(VariantException(var.length));
        //values.require(key, val);

        if(key in values)
        {
          return values[key];
        }
        return val;
      }

      void opDispatch(string key, T)(T val)
      {
        values[key] = val;
      }
    }
  }

  static if(data.length > 0)
  {
    mixin("LookUp2Impl "~data~";");

  } else {

    LookUp2Impl data;
  }
}

import std.stdio;

void main()
{
  enum Tarih
  {
    AY  = 1,
    YIL = 2023
  }
  mixin LookUp2!"date";
  auto deneme1 = date.month; // normalde bu satırda hata veriyordu

  date.month = cast(ubyte)Tarih.AY;
  date.month.write("/");

  assert(date["month"] != Tarih.AY);
  assert(date["month"].type == typeid(ubyte));

  date.year = cast(short)Tarih.YIL;
  date.year.writeln(" in Turkish format");

  assert(date["year"] != Tarih.YIL);
  assert(date["year"].type == typeid(short));

  writefln("Date: %s/%s", date.year, date.month);

  auto deneme2 = date.month;
  assert(deneme2 == 1);
}

Bilmiyorum yöntem nasıl?

Vee tabi, bunu da çok seviyorum! Mixin&AA ikilisi Variant ile güçlendirilmiş. Üstelik Variant&opDispatch işbirliği ile esnek bir kullanım alanı sağlanmış.

Sevgiler, saygılar...

April 15, 2023
On 4/13/23 15:06, Salih Dincer wrote:

> Uninitialized VariantN döndürerek çözdüm:

Variant fazla genel olabilir. Burada eleman türünün T olduğunu biliyoruz. Belki Algebraic kullanılabilir ama onun sayfasında da SumType kullanılması öneriliyor.

> Bilmiyorum yöntem nasıl?

Evet, bir sürü yararlı olanak... Ama amaç var olmama bilgisi ise, Nullable da yeterli:

struct LookUp(T)
{
  T[string] data;

  auto set(string key, T value)
    => data[key] = value;

  auto opIndex(string key) {
      auto ptr = key in data;

      // Nullable!T(*ptr) yerine nullable(*ptr) da olur
      return ptr ? Nullable!T(*ptr) : Nullable!T();
  }
}

Ali

April 18, 2023
On Saturday, 15 April 2023 at 10:11:18 UTC, Ali Çehreli wrote:
> struct LookUp(T)
> {
>   T[string] data;
>
>   auto set(string key, T value)
>     => data[key] = value;
>
>   auto opIndex(string key) {
>       auto ptr = key in data;
>
>       // Nullable!T(*ptr) yerine nullable(*ptr) da olur
>       return ptr ? Nullable!T(*ptr) : Nullable!T();
>   }
> }

Teşekkürler hocam,

Bir de benim gibi switch case'i sık kullananlardansanız, bazen derleyici sıradan İf'lere çevirmek yerine gerçek bir Look-Up Table oluşturur. Buna şurada değindim:

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

Merak eden inceleyebili...


May 03, 2023

On Thursday, 13 April 2023 at 21:21:53 UTC, Ali Çehreli wrote:

>

Parametre değerinin adresini saklamak çok riskli değil mi?

Hocam, araya class Payload koysak sorunu (escaping reference) temelli çözmüş olur muyuz? Örneğin:

struct Lookup(T)
{
	T[string] table;
	alias type = T;

	auto set(string key, ref T value)
		=> table[key] = value;

	auto opIndex(string key)
		=> key in table ? table[key] : T.init;

	auto opSlice()
		=> table.keys;
}

class Payload(T)
{
	
	import std.format : format;
	import std.conv : to;
	
	T data;
	
	this(R)(R data) {
		this.data = data.to!T;
    }
	
	override string toString()
		=> data.format!"Content: %s";
}

void fillTable(R)(ref R data, int loop)
{
	import std.conv : text;
	typeof(data.table).stringof.writeln;

    while(--loop)
    {
        auto key = "ID" ~ loop.text;
        loop.writefln!"Value: %s,  Key: %s"(key);

        auto value = new data.type(loop);
        data.set(key, value);
    }
}

import std.stdio;
void main()
{
	alias PL = Payload!int;

	Lookup!PL table;
	table.fillTable(10);

	table["ID4"].writeln;
	table["ID1"].writeln;
} /* ÇIKTISI:

Payload!int[string]
Value: 9,  Key: ID9
Value: 8,  Key: ID8
Value: 7,  Key: ID7
Value: 6,  Key: ID6
Value: 5,  Key: ID5
Value: 4,  Key: ID4
Value: 3,  Key: ID3
Value: 2,  Key: ID2
Value: 1,  Key: ID1
Content: 4
Content: 1

*/

Teşekkürler...

May 03, 2023

On Wednesday, 3 May 2023 at 13:32:09 UTC, Salih Dincer wrote:

>
/* ÇIKTISI:

Payload!int[string]
Value: 9,  Key: ID9
Value: 8,  Key: ID8
Value: 7,  Key: ID7
Value: 6,  Key: ID6
Value: 5,  Key: ID5
Value: 4,  Key: ID4
Value: 3,  Key: ID3
Value: 2,  Key: ID2
Value: 1,  Key: ID1
Content: 4
Content: 1

*/

Bir de şunu deneyin, bence güzel yani :)

	import std.algorithm : each;
	table[].each!((a) => table[a].data.write(", "));
	writeln; // "4, 2, 9, 6, 5, 3, 1, 8, 7,"

Elbette table, sıradan bir Associative Array olabilirdi ve değerleri listelemek daha kolay olurdu. O zaman da pekala şöyle basit bir çıktı alabilirdik:

	table.values.writef!"%-(%s, %)";
	writeln; // "4, 2, 9, 6, 5, 3, 1, 8, 7"

Özetle ne öğrendik? Boşuna bir çaba mı? Faydası ne olabilirdi?

May 03, 2023
On 5/3/23 06:32, Salih Dincer wrote:
> On Thursday, 13 April 2023 at 21:21:53 UTC, Ali Çehreli wrote:
>> Parametre değerinin adresini saklamak çok riskli değil mi?
>
> Hocam, araya `class Payload` koysak sorunu (escaping reference) temelli
> çözmüş olur muyuz?

Kullanıcıyı class kullanmaya zorlamış olmaz mıyız? Eğer uygunsa tamam... diyeceğim ama o zaman 'scope' ile oluşturulmuş sınıf nesneleri de kullanılamaz herhalde. (?)

Ne olursa olsun, Lookup'ın Payload'dan haberi olmadığına göre, Lookup'ın doğru çalışması sağlanmalı.

>      auto set(string key, ref T value)
>          => table[key] = value;

Parametrenin 'ref' olmasının bir anlamı yok herhalde çünkü zaten T[string]'e kopyalanacak.

Burada "bu da olmamış" demeye çalışmıyorum çünkü ne yapmaya çalıştığımızı tam anlamıyorum. Benim göstermeye çalıştığım tek şey, parametrenin adresinin saklanmasının genelde yanlış olacağıydı.

Ali

May 03, 2023

On Wednesday, 3 May 2023 at 14:14:37 UTC, Ali Çehreli wrote:

>

Kullanıcıyı class kullanmaya zorlamış olmaz mıyız?

Hayır, çünkü sınıf sadece bir payload; yani taşıyıcı. Ve taşıyacağı yükü programcı belirleyebilir. Bu uygulamanın faydası, programcının karşılaşabileceği "Range violation" hatalarından korumak ve in işleçi yerine is ile null kontrolü sağlamasına yardımcı olmak. Bunu yaparken Variant veya Nullable kullanma ihtiyacı bırakmaması ayrı bir avantaj. Örneğin:

import std.stdio, std.conv : text;

void main()
{
	alias PL = Payload!string; // Programcı dilerse string de kullanabilir.

	Lookup!PL table;
	table.fillTable(10);

	auto test1 = table["ID10"];
	assert(test1 is null);

	int[string] tablo;
	int loop = 10;
	
	while(--loop)
	{
		tablo["ID" ~ loop.text] = loop;
	}
	
	// auto test2 = tablo["ID10"];
	// RangeError: Range violation

	tablo.values.writef!"%-(%s, %)";
	writeln; // "4, 2, 9, 6, 5, 3, 1, 8, 7"
}

On Wednesday, 3 May 2023 at 14:14:37 UTC, Ali Çehreli wrote:

>

Parametrenin 'ref' olmasının bir anlamı yok herhalde çünkü zaten T[string]'e kopyalanacak.

Emin değilim ama ref kullanmadığım zaman veriye erişim sağlayamadım.

Sevgiler, saygılar...

May 03, 2023
On 5/3/23 07:40, Salih Dincer wrote:

>      auto test1 = table["ID10"];
>      assert(test1 is null);

Yani, 'null' geçerli bir değer olamayacak. Öyleyse tamam. Nullable önerisi, kullanıcının 'null'ı da değer olarak saklamak istediği durumlar içindi. (Yani, "ID10" var da değeri mi 'null' yoksa "ID10" tabloda yok mu; onu anlayamıyoruz.)

Ali

« First   ‹ Prev
1 2