Thread overview
@property'e ihtiyacımız olan bir durum!
Nov 19, 2022
Salih Dincer
Nov 19, 2022
Ali Çehreli
Nov 21, 2022
Salih Dincer
Nov 21, 2022
Ali Çehreli
Dec 18, 2022
Salih Dincer
Dec 19, 2022
Ali Çehreli
Dec 20, 2022
Salih Dincer
Dec 20, 2022
Ali Çehreli
Dec 21, 2022
Salih Dincer
Dec 23, 2022
Salih Dincer
November 19, 2022

Merhaba,

Teknik olarak çok fazla açıklamasını bilmiyorum ama alias ... this ile bağlayıp inout özellikli bir işlevi ikiliyi @property kullanmadığımızda doğru çalışmayacağını garanti eden bir yapımız var:

struct FixedStr(size_t capacity)
{
  char[capacity] data = ' ';
  char[] buff;

  this(string _data) {
    buff = data[];
    this ~= _data;
  }
  alias opReturn this;

  //* v--- bu olmayınca farklı sonuç* alınıyor!
  @property //*/
  auto opReturn() inout
    => data[6..$]; // cuts off the header

  auto ref opOpAssign(string op)(string arr) if(op == "~")
    => buff.put(arr); // add in the data
}

Yukardaki gibi 2 işlevli (sondaki işleç yükleme) bir yapımız olsun. Aslında işlevlerin doğrudan kullanıma açık bir özelliği yok. Yani yok hükmünde düşünün ki zaten opReturn() gibi bir işleç yükleme yok, benim uydurmam :)

Yaptığı ise basit: Sabit (fixed) bir char dizisini baştan kırparak döndürmek (dış dünyaya açmak) ve sınırına kadar içine sırayla (std.range.put marifetiyle) veri eklemek. Ancak bunu tanıdık olduğumuz string gibi kullanmak (örneğin 2. satır çıktısı: "two") da istiyoruz. Test etmek için ise şu kodu kullanabilirsiniz:

// (*): FixedStr!21LU("Veri: six, two, one, ", "")
import std.stdio, std.format;
import std.range;

void main()
{
  enum text = "sixtwoone";
  auto test = FixedStr!21("Veri: ");
  foreach(num; text.chunks(3))
  {
    test ~= num.format!"%s, ";
  }
  test.writeln; // six, two, one,
  test[6..9].writeln; // two
}

Tamam, bu sorunun çözümü en basit şekilde varsayılan toString() üzerine kendimiz bir şeyler yazmak olabilir ama o zaman alias ... this gibi işlevsel bir çıktı (kurulurken veriyle eklenen başlığı silmek) elde edemeyiz ve dilimleneni dilimleyemeyiz.

Özetle neden writeln() ile ekrana yazarken @property'e ihtiyaç duyduk? Aslında sebebini tahmin edebiliyorum. Ali hoca bize bunu, derlenirken pragma mesajı ile göstermişti. Sanırım bir işlev nesnesi gibi sonunda çift parantez => "opReturn()" gözükmesi bunu sağlıyor!

Dip Not: Aradaki farkı görmek için gizlenen @property üstündeki çiftli yorum satırını teke düşürmeniz yeterli.

Sevgiler, saygılar...

November 19, 2022
On 11/19/22 06:41, Salih Dincer wrote:
>  bize bunu,
> derlenirken `pragma` mesajı ile

pragma(msg)'ın bir güzelliği, 'import std.stdio' filan demek gerekmediğinden kod daha kısa oluyor. :)

> `@property`

Haklısın. Bu olanaklar pek kullanılmadığından olsa gerek, birbirleriyle etkileşimleri de garip olabiliyor.

Olabildiğince basit kodlarla göstererek bildirmek yararlı olacaktır. Örneğin, opReturn gibi isimler kullanmak karışıklık yaratacaktır; ben oun araştırdım ve kendimi D1 olanağı olduğuna inandırdım. Ondan sonra senin yazdığını okuyunca anladım. :/

Ali

November 21, 2022
On Saturday, 19 November 2022 at 19:28:05 UTC, Ali Çehreli wrote:
> Olabildiğince basit kodlarla göstererek bildirmek yararlı olacaktır.

Açıkcası boşuna kürek çekmek olduğunu düşünüyorum. Hani birlikte bulduğumuz ve bildirimini eylülün başında yaptığın hata, unutulmuşa benziyor:

https://issues.dlang.org/show_bug.cgi?id=23319
November 20, 2022
On 11/20/22 20:36, Salih Dincer wrote:

> eylülün başında yaptığın hata, unutulmuşa benziyor:

Şu anda toplam 4590 bug görüyorum. En eskisi, Haziran 2010'dan:

  https://issues.dlang.org/show_bug.cgi?id=4361

Sırayla düzeltilmiyorlar tabii. Kim önemli olduğuna da bakarak yapabilecek zaman bulup ilgilenebiliyorsa...

Ali

December 18, 2022

On Monday, 21 November 2022 at 05:02:48 UTC, Ali Çehreli wrote:

>

On 11/20/22 20:36, Salih Dincer wrote:

>

eylülün başında yaptığın hata, unutulmuşa benziyor:

Şu anda toplam 4590 bug görüyorum. En eskisi, Haziran 2010'dan:

https://issues.dlang.org/show_bug.cgi?id=4361

Neyse ki yamandı, çok mutluyum :)

Bugün öğrenmelik bir şeyler denedim. Deneme sayısı arttıkça bazı kırpmalar, bazı kolaylıklar keşfettim. Normalde dış dünya açmak istemediğim durumlar olursa sarma (wrapping) tercih ediyorum. Haliyle onu iyice haberleştirmek gerekiyor ki bir bakıyorum tüm aşırı yüklemelere şöyle dokunmuşum. Ta ki bugüne kadar ilginç sonuçlar çıktı!

Sizce de tekli operatör (opUnary) aşırı yüklemesine ihtiyaç duymaması ilginç değil mi?

import std.stdio;

struct S
{
  private int value;

  alias opCall this;
  this(int i) {
    value = i;
  }

  alias opAssign = opCall;
  @property opCall(int x) {
    return value = x;
  }

  @property opCall() inout {
    return value;
  }

  @property opOpAssign(string op)(int x) {
    write(":"); // daha önce burdan geçtim!
    mixin("return value"~op~"=x;");
  }
  // gerek yok :) opUnary(string op)();
}

void main()
{
  S a = S(10),
    b = S(-1);

  writeln(a + b); // 9
  writeln(++a + b); // :10

  a += 10; // :

  assert(a == 21);
  writeln("\n--");

  writeln(-b); // 1
}

Sevgiler, saygılar...

December 19, 2022
On 12/18/22 08:33, Salih Dincer wrote:

> Sizce de tekli operatör (opUnary) aşırı yüklemesine ihtiyaç duymaması
> ilginç değil mi?

Evet, garip.

Ali

December 20, 2022

On Monday, 19 December 2022 at 20:05:33 UTC, Ali Çehreli wrote:

>

On 12/18/22 08:33, Salih Dincer wrote:

>

Sizce de tekli operatör (opUnary) aşırı yüklemesine ihtiyaç
duymaması
ilginç değil mi?

Evet, garip.

Ali

Peki hocam bu garip yapıyla(Nx) yaşanabilir mi! Misal aşağıda, D için ChatGPT'de complex sayılar kod parçacığı yazmasını istedim ve sarmaladıklarımın başına sadece Nx! ekledim, çalıştı! Gelecek sürümlerde bu kod patlar mı, @property'i body gibi iptal ettik derler mi çünkü kod o zaman çökmese de ekran çıktısı bozuk gözükecektir.

import std.stdio;

alias Cmplx = ComplexNumber;
class ComplexNumber
{
    Nx!double real_;
    Nx!double imag_;

    this(double r = 0.0, double i = 0.0) {
      real_(r);
      imag_(i);
    }

    Cmplx opBinary(string op)(Cmplx other)
    if (op == "+") {
        return new Cmplx(real_ + other.real_,
                         imag_ + other.imag_);
    }

    Cmplx opBinary(string op)(Cmplx other)
    if (op == "-")
    {
        return new Cmplx(real_ - other.real_,
                         imag_ - other.imag_);
    }

    Cmplx opBinary(string op)(Cmplx other)
    if (op == "*")
    {
        return new Cmplx(real_ * other.real_
                       - imag_ * other.imag_,
                         real_ * other.imag_
                       + imag_ * other.real_);
    }

    Cmplx opBinary(string op)(Cmplx other)
    if (op == "/")
    {
        auto divX = other.real_ * other.real_
                  + other.imag_ * other.imag_;
        return new Cmplx((real_ * other.real_
                        + imag_ * other.imag_) / divX,
                         (imag_ * other.real_
                        - real_ * other.imag_) / divX);
    }

    override string toString() const
    {
      import std.format;
      return format("%s + %si", real_, imag_);
    }
}

void main()
{
    Cmplx a = new Cmplx(1, 2);
    Cmplx b = new Cmplx(3, 4);

    Cmplx c = a + b;
    writeln(c.toString()); // Output: "4 + 6i"

    Cmplx d = a - b;
    writeln(d.toString()); // Output: "-2 - 2i"

    Cmplx e = a * b;
    writeln(e.toString()); // Output: "-5 + 10i"

    Cmplx f = a / b;
    writeln(f.toString()); // Output: "0.44 + 0.08i"
}

struct Nx(Type)
{
  private Type value;

  this(Type i) {
    value = i;
  }

  alias opCall this;
  alias opAssign = opCall;

  @property opCall(Type x)
  {
    return value = x;
  }

  @property opCall() inout
  {
    return value;
  }

  Type opOpAssign(string op)(Type x)
  {
    mixin("return value"~op~"=x;");
  }
}

Saygılar...

December 20, 2022
On 12/20/22 06:17, Salih Dincer wrote:

> bu garip yapıyla(Nx) yaşanabilir mi!

Olabilir. Kurucu içinde 'real_ = r' yapamamak dışında bir farklılık görmedin, değil mi?

> @property'i body gibi iptal ettik derler mi

Onunla ne ilgisi var diye düşündüm ve o sorunun yanıtını geçen gün verdiğini tekrar hatırladım: @property yazmayınca Nx'in varsayılan toString'ini kullanıyor ve çıktı şöyle oluyor:

  const(Nx!double)(4) + const(Nx!double)(6)i

Yani, @property'nin 'alias this' ile etkileşiminin bilmediğimiz bir etkisini görüyoruz ama bütün bu bilgi, içinde başka olanaklar da içeren Nx gibi bir yapı içinde kayboluyor. Ben İngilizce forumda uzun uzun inceleyerek neyin neyi çağırdığını anlamaya çalışmıştım.

@property'nin bu ilginçliğini daha kısa bir kodla ifade edebilir miyiz acaba? Buldum:

import std;

struct S {
    /* @property */ int foo() const {
        return 42;
    }

    alias foo this;
}

void main() {
    writeln(S());
}

Evet, olay ondan ibaret: 'alias this', @property'li bir işlevle kullanıldığında nesne değil, @property'li işlevin işletilmesinin sonucu kullanılıyor. Bu da toString'i olmayan yapının nasıl yazdırıldığını bile etkiliyor. Hatta, acaba bu yalnızca writeln ile ilgili bir şey mi?

Ali

December 21, 2022

On Tuesday, 20 December 2022 at 16:20:34 UTC, Ali Çehreli wrote:

>

On 12/20/22 06:17, Salih Dincer wrote:

>

bu garip yapıyla(Nx) yaşanabilir mi!

Olabilir. Kurucu içinde 'real_ = r' yapamamak dışında bir farklılık görmedin, değil mi?

Evet, onu dışarıda pekala halledilebilir. Bir başka örnek:

void main()
{
  import std.stdio;

  auto p1 = Point(1, 2);
  auto p2 = Point(10, 20);
  writeln(p1 + p2);

  class Foo { Bar!Point point; }

  auto foo = new Foo;
  foo.point = p1;
  writeln(foo.point + p2);
}

struct Bar(T) {
  private T bar;
  alias opCall this;

  @property opCall() inout
  {
    return bar;
  }

  @property opCall(T c)
  {
    return bar = c;
  }
}

struct Point {
  int x, y;
  pure const nothrow @safe:

  auto opBinary(string op)(in Point rhs) @nogc {
    return Point(mixin("x" ~ op ~ "rhs.x"),
                 mixin("y" ~ op ~ "rhs.y"));
  }

  auto opBinary(string op)(int rhs) @nogc {
    return Point(mixin("x" ~ op ~ "rhs"),
                 mixin("y" ~ op ~ "rhs"));
  }
}

>

Evet, olay ondan ibaret: 'alias this', @property'li bir işlevle kullanıldığında nesne değil, @property'li işlevin işletilmesinin sonucu kullanılıyor. Bu da toString'i olmayan yapının nasıl yazdırıldığını bile etkiliyor. Hatta, acaba bu yalnızca writeln ile ilgili bir şey mi?

Aslında o çok önemli değil hocam. Sonuçta matematiksel işlemler yapan ve ekrana grafik çizen bir program için sıkıntı değil. Haa keza yukardakin kodun çıktısı şu şekilde:

>

Point(11, 22)
Point(11, 22)

Teşekkürler...

December 23, 2022

On Tuesday, 20 December 2022 at 14:17:50 UTC, Salih Dincer wrote:

>

Gelecek sürümlerde bu kod patlar mı, @property'i body gibi iptal ettik derler mi çünkü kod o zaman çökmese de ekran çıktısı bozuk gözükecektir.

import std.stdio;

alias Cmplx = ComplexNumber;
class ComplexNumber
{
    Nx!double real_;
    Nx!double imag_;

    this(double r = 0.0, double i = 0.0) {
      real_(r);
      imag_(i);
    }

//...

Meğer Nx() yapısı içine, varsayılan kurucu yerine kendi kurucunuzu dahil ettiğinizde istediğimiz/alıştığımız şu şekilde kullanıyormuş da...

    this(double r = 0.0, double i = 0.0) {
      real_ = r;
      imag_ = i;
    }

...dikkatlerimizden kaçmış! Meğer aşkın (complex) sayılar ile ilgili verdiğim yukardaki örnek tammış, elimin altındaymış!

Şu mübarek cuma sabahı ancak fark ediyorum, evet itiraf ediyorum : beyin sulanması böyle bir şeymiş 😀

Başarılar...