C# 15'te Union Types ve Kapalı Hirarşiler: Tip Güvenliği ve Esneklik İçin Bir Atılım

C# 15'te Union Types ve Kapalı Hirarşiler: Tip Güvenliği ve Esneklik İçin Bir Atılım
audio-thumbnail
C# 15'te Union Types ve Kapalı Hirarşiler: Tip Güvenliği ve Esneklik İçin Bir Atılım
0:00
/0

C# 15'te Union Types ve Kapalı Hirarşiler: Tip Güvenliği ve Esneklik İçin Bir Atılım

C# 15, .NET 11 ile birlikte tanıtıldı ve bu sürümle birlikte geliştiricilerin yıllardır beklediği Union Types (Birleşim Tipleri) ve Kapalı Hirarşiler (Closed Hierarchies) gibi güçlü tip sistemleri, C#'ın tip güvenliği ve esnekliğini önemli ölçüde artırdı. Bu gelişmeler, özellikle büyük ölçekli uygulamalarda hata oluşmasını önleyen, daha güvenli ve tutarlı kod yazmaya olanak tanıyan yeni bir dönem başlatıyor.

Bu makalede, C# 15'teki bu yeniliklerin nasıl çalıştığını, neden önemli olduklarını ve geliştiricilerin bu özelliklerden nasıl yararlanabileceğini inceleyeceğiz.


Union Types: "İki Tip, Bir Değer" Mantığı

C# 15'te tanıtılan union anahtar kelimesi, bir değerin birden fazla türden biri olabileceğini belirtir. Bu, F# ve Elm gibi dilde uzun süredir kullanılan ayrıştırılmış birleşimler (discriminated unions) kavramına benzer bir yaklaşımı temsil ediyor.

Örnek olarak, bir hayvan türüne sahip bir uygulama düşünün:

public record Cat(string Name);
public record Dog(string Name, int Age);
public union Pet(Cat, Dog);

Bu tanım, Pet tipinin ya Cat ya da Dog olabileceğini belirtir. Her iki tür de otomatik olarak Pet tipine dönüştürülebilir:

Pet pet = new Dog("Fido", 3);

Switch İfadeleri ve Tümel Kapsam (Exhaustiveness)

C# 15'te switch ifadeleri, union tipine uygulandığında tüm olası değerleri kontrol eder. Bu, derleyicinin sadece mevcut durumları değil, tüm olası durumları bildiğini biliyor olması demektir.

Örneğin:

static string Describe(Pet pet) => pet switch
{
    Cat c => $"{c.Name} the cat",
    Dog d => $"{d.Name} the dog, age {d.Age}",
};

Bu kod, herhangi bir Pigeon gibi yeni bir tür eklendiğinde, derleyici bir uyarı verir:

CS8509: Switch ifadesi giriş türünün tüm olası değerlerini ele almıyor. Örneğin 'Pigeon' patterni kapalı değil.

Bu, "impossible states made impossible" (imkansız durumlar imkansız hale getirilir) yaklaşımını temsil eder. Kullanıcı, programın bu durumlara karşı korunmuş olduğunu bilir.


Hata Kontrolü: Uyarı mı, Hata mı?

C# 15, bu tür eksiklikleri uyarı olarak verir. Yani program derlenir ve çalışır, ancak bir Pigeon nesnesi Describe fonksiyonuna girdiğinde çalışma zamanı hatası oluşur.

Bu, F# ile aynı yaklaşımı yansıtır. Ancak Elm gibi bazı dillerde bu durum derleme hatası olarak kabul edilir:

"Bu case tüm olasılıkları kapsamıyor. Örneğin Pigeon _ olasılığı kapalı değil."

C# ve F#'ın bu "yumuşak" yaklaşımı, geliştiricilere esneklik sağlar, ancak hata kontrolünü geliştiricinin eline bırakır. Bu nedenle, bir proje için bu uyarıları hata olarak ayarlamak en iyi uygulamadır:

#property WarningsAsErrors=CS8509

Bu, eksik durumlar varsa derleme başarısız olur ve geliştirici hata tespiti yapar.


Switch İfadeleri mi, Switch Deyimi mi?

Dikkat edilmesi gereken önemli bir ayrıntı: Sadece switch ifadeleri tümel kapsama kontrolü yapar. switch deyimleri ise bu kontrolü yapmaz.

Pet pet = new Pigeon("Kevin");
switch (pet)
{
    case Cat c: Console.WriteLine($"feed {c.Name} some fish"); break;
    case Dog d: Console.WriteLine($"walk {d.Name}"); break;
}

Bu kod, Pigeon nesnesi geldiğinde herhangi bir işlem yapmaz ve done yazdırılır. Derleyici bu durumu görmez.

Bu, C# 15'in kullanıcı davranışına bağlı olduğunu gösterir. Yani, geliştirici, güvenliği sağlamak için switch ifadeleri kullanmalıdır. Bu nedenle, var olan kodlara bu yeni yapının entegre edilmesi için bir analizör (analyzer) gerekebilir.


Union Types: Tip Bazlı, Etiketli Değil

C# 15'teki union tipinin en büyük farkı, etiket temelli değil, tip bazlı olmasıdır. F# veya Elm'de:

type ContactInfo = Email of string | Phone of string

Burada Email ve Phone gibi etiketler vardır. Ancak C#’da:

public union ContactInfo(string, string);

Bu kod hata verir:

CS0111: 'ContactInfo' tipi zaten aynı parametre tiplerine sahip bir 'ContactInfo' üyeyi tanımlıyor.

C#'ın union tipi, her bir durumun ayrı bir tür olması gerektiğini kabul eder. Bu da geliştiricileri, bir domain tipi olarak EmailAddress veya PhoneNumber gibi bir yapı kurmaya teşvik eder.

Bu yaklaşım, hem temiz kod hem de tip güvenliği açısından faydalıdır. Scott Wlaschin’in “domain-driven design” felsefesini destekler.


Genel Tipler ve Ambigüite

Bu yaklaşım, genel tiplerde de sorunlar doğurabilir. Örneğin:

public union Result<T, E>(T, E);
Result<int, string> ok = 42; // tamam
Result<string, string> uhOh = "is this an error?"; // hata

Derleyici şu hatayı verir:

CS0457: 'Result' tipinden 'string' tipine dönüşümde kullanıcı tanımlı dönüşüm belirsiz.

Neden? Çünkü Result<string, string> türünde, string tipinden Result<string, string> tipine dönüşüm yaparken, ikisi de aynı tipten olabilir. Derleyici hangi dönüşümü seçeceğini bilemez.

Bu, genel tiplerde tutarlılık sağlamaya çalışan C# 15’in bir sınırlamasıdır. Ancak bu, geliştiricinin tip tasarımında daha dikkatli olması gerektiğini gösterir.


Kapalı Hirarşiler: Geleceğin Tip Sistemleri

C# 15'teki union tipi, kapalı hirarşiler (closed hierarchies) kavramını temsil eder. Yani bir tipin tüm alt türlerinin bilinmesi ve derleyicinin bu bilgiyi kullanabilmesidir.

Bu, C#'ın tip sistemine çok daha güçlü bir yapı kazandırır. Özellikle:

  • Tümel kapsama kontrolü
  • Hata yakalama
  • Kod okunabilirliği
  • Kod güvenliği

gibi alanlarda büyük bir ilerleme sağlar.


Sonuç: Bir Atılım, Bir Dönem

C# 15, tip güvenliği ve esneklik açısından büyük bir atılım olarak görülüyor. Union Types ve Closed Hierarchies, C#'ın tip sistemini, daha fazla güvenlik, tutarlılık ve kod üretimi açısından geliştiriyor.

Ancak bu yenilikler, geliştiricilerin yeni davranışlar öğrenmesini gerektirir. Özellikle switch ifadeleri ile switch deyimleri arasındaki fark, kullanım alışkanlıklarını değiştirir.

Bu gelişmeler, C#'ın daha fazla fonksiyonel dil özelliklerine doğru ilerlemesinin bir göstergesidir. Gelecekte, C# daha fazla tip güvenliği, daha az hata ve daha çok otomatik kontrol ile geliştiricileri destekleyecek.

Eğer hata oluşmasını istemiyorsan, uyarıları hata yap. Eğer hedefin daha iyi bir tip sistemi ise, C# 15'i öğren. Çünkü bu, geleceğin tip sistemleri için bir başlangıç.