November 07, 2022
D'deki bazı olanakların keyfi kullanımları kod kalitesini düşürüyor diye düşünüyorum. Sizlerin özellikle kaçındığı veya kendi kodunuzda kullanmayacağınız kurallarınız var mı? Özellikle hata yakalama konusunda neler yaptığınızı, throw Exception()'ları kullanıp kullanmadığınızı merak ediyorum.

// alias asla kullanılmamalı, ama okunaklılığı azaltıyorsa.

alias string = (immutable char)[];
// Artık elemanların immutable olduğunu bilmiyoruz.

void main(string[] args);
// Artık 'array of that array of some immutable chars' ifadesini 'array of string'
// olarak biliyoruz.

// alias'ların kullanmaya değer olduğu durumlar 'inline scope' olarak
// tanımladığımız yerler olduğunu düşünüyorum. Fakat 'inline import' bu
// işi bizim için zaten yapıyor.

{
    alias Actor = game.classes.Actor;
    Actor actor;
}
{
    import game.classes: Actor;
    Actor actor;
}

// alias'lar derleme zamanı olanakları ile kullanıldıklarında daha işlevseller.
// (bkz. template'ler)


November 07, 2022
On 11/7/22 08:31, dunecourser wrote:
> D'deki bazı olanakların keyfi kullanımları kod kalitesini düşürüyor diye
> düşünüyorum.

Kalite, okunurluğu da kasdettiğini düşünüyorum. Katılıyorum.

> Sizlerin özellikle kaçındığı veya kendi kodunuzda
> kullanmayacağınız kurallarınız var mı?

D'nin en güzel taraflarından birisi, olabildiğince basit yazıp sonra gerektikçe değiştirmek.

Kodu yazmaya başladığımda:

- private, scope, @safe, nogc, vs. kullanmıyorum

- Yalnızca aptal struct'lar ve serbest işlevler yazıyorum

Gerektikçe bazı işlevler üye işlev haline geliyor, veya kurucu, vs. yazıyorum.

> Özellikle hata yakalama konusunda
> neler yaptığınızı, throw Exception()'ları kullanıp kullanmadığınızı
> merak ediyorum.

'throw'u hiçbir zaman açıkça kullanmıyorum:

- Giderilebilir hatalar için (veya "kullanıcı" hataları için) Exception atarken:

  enforce(birKoşul, format!"Geçersiz değer: %s"(birDeğer));

- Giderilemez program hataları için Error atarken:

  assert(birKoşul, format!"Geçersiz değer: %s"(birDeğer));

Zaten sözleşmeli programlama (contract programming) olanakları da Error atar.

İlgili olarak, main işlev de şunun eşdeğeri oluyor:

int main(string[] args) {
    try {
        işlet(args);
        return 0;

    } catch (Exception hata) {
        import std.stdio : stderr, writefln;
        import std.format : format;

        stderr.writefln!"HATA: %s"(hata.message);
        return 1;
    }
}

void işlet(string[] args) {
    // Programın asıl giriş noktası...
}

Dikkat edersen, Error yakalanmıyor çünkü o zaman hangi noktada patladığını görmek için "stack trace" istiyoruz.

Bazen, kodu yazarken bir Exception'ın bile ne durumda patladığını görmek için şu değişikliği yapıyorum:

  hata.message yerine yalnızca 'hata'.

O zaman "stack trace" yazdırılıyor.

> // alias asla kullanılmamalı, ama okunaklılığı azaltıyorsa.

alias'ı kullanıyorum, okunaklılığı arttırıyorsa. :)

> alias string = (immutable char)[];
> // Artık elemanların immutable olduğunu bilmiyoruz.

Ondan kaçış yok. string D'nin her yerinde ve zaten o yazdığının aynısı.

Bazı insanlar şunu da yapıyorlar:

alias stringc = const(char)[];

> // alias'ların kullanmaya değer olduğu durumlar

Son zamanlarda yazmış olduğum kodda şunları buluyorum:

    alias ET = ElementType!R;
    alias invalidSliceOffset = CachedRange!ElementCache.invalidSliceOffset;
    alias BlockSlice = typeof(elements[]);
    alias TD = Tuple!Data;

Şunun gibi kullanımları farklı kabul etmek gerek çünkü AliasSeq kullanırken gerekiyor. Bir unittest bloğundan:

    alias Ts = AliasSeq!(const(int), 42,
                         immutable(double), 1.5,
                         const(S), S("hello"));

    static foreach (i; 0 .. Ts.length)
    {
        // ...
    }

Evet, ayrıca alias'lara gerek yok ama örneğin AliasSeq'li ifadeyi 'static foreach'e doğrudan yazmak daha karmaşık olur diye düşünmüşüm. Kendime hâlâ katılıyorum. :)

Ali