Immutable Type Kavramı

Immutable tipler, değişmeyen tiplerdir. Yani herhangi bir nesneyi bellekte bir kere oluşturduktan sonra daha da stateini değiştiremezsiniz. Immutable type objeleri kendimiz yaratabildiğimiz gibi aslında bilmeden çokça kullanılıyoruz. Immutable type denilince ilk akla gelen örnek string’tir. String immutable yani değiştirilemez bir tiptir. Bir kere yaratırsınız daha da değiştiremezsiniz. Kulağa biraz garip geliyor değil mi? Hepimiz kullandığımız dillerde string değişkenimizi alıp replace ederek, ya da + operatorüyle birşeyler ekleyerek veya string metotlarıyla üzerinde değişiklikler yapıyoruz. Öyle değil mi? Aslında değil 🙂 Şimdi konunun biraz daha detaylarına inelim.

String gibi Immutable tipleri değiştirirken aslında değiştirmek yerine bir klonunu tanımlayıp onun üzerinden işlem yapıyoruz. Yani aslında stringleri değiştirdiğimizi düşünerek yaptığımız tüm operasyonlar bize yepyeni bir string yaratıyor. Aşağıda internetten bulduğum bir görsel durumu çok güzel özetlemiş. E o zaman immutable bir tiple çalışırken, farkında olmadan büyük performans kayıpları ortaya çıkarabiliriz. Düşünsenize, upuzun satırlarca MB’ler boyutunda stringleriniz var ve siz her birinin sonuna ufacık bir ekleme yaparak operasyon yapıyorsunuz. Ancak o ufak eklemeden dolayı her seferinde bellekte yepyeni bir string yaratılıyor 🙂 .  Olaya bir başka pencereden daha bakalım. Dillerde kullandığınız string metotları, toLower, toUpper vs. hiç birisi aslında sizin elinizdeki stringi değiştirmiyor. Dikkat ettiyseniz, hepsi size yepyeni bir string return ediyor. Çünkü zaten yepyeni bir string yaratıyorlar.

Peki bu memory israfını önlemenin bir yolu yok mu?  Yukarıda bahsettiğimiz gibi, bir kod bir string üzerinde binlerce işlem yapıyorsa, heap’te istenmeyen, boşa harcanan belleğe yol açan binlerce kullanılmayan string nesnesi olacaktır. Neyse ki, StringBuilder sınıfını kullanarak bunu önleyebiliriz.

Kendi immutable type’ımızı yaratabilir miyiz?

Evet yaratabiliriz. Aslında stepleri de çok basittir. Oluşturduğunuz class’ın tüm fieldlarının setterlarını silip, readonly yaparak sadece constructordan initialize edilecek hale getirirseniz yarattığınız nesne değiştirilemez yani immutable olmuş olur. En basit örneğiyle, aşağıdaki Person classı bir kere yaratılıp, fieldlar initialize edildikten sonra değiştirilemediği için immutable bir yapıdadır diyebiliriz.

public class ImmutableClass
{
    private readonly string _name;
    private readonly string _surname;

    public string name
    {
        get
        {
            return _name;
        }
    }
    public string surname
    {
        get
        {
            return _surname;
        }
    }
    public ImmutableClass(string name, string surname)
    {
        this._name = name;
        this._surname= surname;
    }
}

“Classes should be immutable unless there’s a very good reason to make them mutable….If a class cannot be made immutable, limit its mutability as much as possible.”

Immutable objectler genelde multi threading yapısı kullanıdığımız uygulamada işe yarar ve sizi  race condition’dan kurtarır. Immutable objectleri stateleri değiştirilemediğinden o nesneyi kaç thread kullanırsa kullansın o nesne üzerinde değişiklik yapamaz. Bu durumda, siz de threadler arasındaki senkronizasyonu sağlayacak mekanizmaları yazmaktan kurtulursunuz ve otomatik olarak yazdığınız tip thread-safe olur.

Ancak stringlerin immutable olmasıyla ilgil başka bir ayrıntı daha var. Siz kod içerisinde aynı değere sahip farklı değişkenlere atanmış stringler oluşturduğunuzda aslında, bellekte aynı değere sahip yeni stringler yaratılmıyor. Bunun yerine tüm değişkenler aynı stringle mapleniyor. Aşağıda, iki adet string aynı değere sahip. İlk bakışta sanki heap’de iki adet yer ayrılmış ve ikisinde de “Merhaba Dünya” değeri var gibi geliyor olabilir. Ancak öyle değil. Tek bir alan ve tek bir “Merhaba Dünya” değeri vardır ve iki string de bu alana refere eder. E peki o zaman “a” üzerinde yaptığımız bir değişiklik neden diğer “b” ye de etki etmiyor? Dedik ya zaten değişiklik yapamıyoruz diye 🙂 Klonlanıp klonu üzerinden işlem yapıyoruz . Yani immutiblity.

Dolayısıyla aşağıdaki kod blogunda ilk if’e girilecek olup, ikinci if’e girilmeden atlanacaktır.

 static void Main(string[] args)
 {

      string a = "Merhaba Dünya";
      string b = "Merhaba Dünya";

      if(Object.ReferenceEquals(a, b))
      {
         Console.WriteLine("İki değişken aynı alanı kullandiği için bu koşula girildi.");
      }

       a += " güncel";

      if(Object.ReferenceEquals(a, b))
      {
          Console.WriteLine("a değişkenine yapılan değişiklik a'nın klonlanıp heapte yeni bir alanda oluşturulmasına sebeğ olduğu için bu if atlanacak.");
      }
}

You may also like...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir