İlkay İlknur

just a developer...

Immutable Collections

Bir önceki yazimizda Immutable Nesnelerden bahsetmistik ve gerekli durumlarda kendi Immutable nesnelerimizi nasil yazabilecegimizi görmüstük. Yine ayni yazinin sonlarinda hatirlarsaniz Immutable Collectionlardan kisaca bahsetmistim.

Bu yazimizda ise Immutable Collectionlari biraz daha detayli bir sekilde inceleyecegiz.

Immutable Collectionlar da aslinda baktigimizda Immutable Nesne mantiginin collectionlar üzerinde implemente edilmis hali. Basit olarak siz bir Immutable Collection yaratirken collection içerisinde bulunacak olan elemanlari veriyorsunuz ve sonrasinda bu collection içerisinde bir degisiklik yapamiyorsunuz. Eger bir Immutable Collection içerisine eleman eklemek veya silmek isterseniz yani collectionin state'ini degistirmek isterseniz de bu state'i tasiyacak olan yeni bir collection yaratmak zorundasiniz. Böylece elinizde bulunan collectionin thread-safe oldugunu garanti altina almis oluyorsunuz. Çünkü elinizdeki collectiona isteginiz kadar thread ayni anda ulassin collection üzerinde bir degisiklik yapmalari mümkün degil.

Simdi gelelim Immutable Collections'i nasil kullanacagiz konusuna...

Microsoft Immutable Collections Nuget Package

Uygulamalarinizda yukarida bahsettigim Immutable Collectionlari kullanmak isterseniz Microsoft tarafindan gelistirilen Immutable Collections Nuget paketini kullanabilirsiniz. Bu paketi projenize eklemeniz için asagidaki komutu yazmaniz yeterli.

PM> Install-Package Microsoft.Bcl.Immutable

Yukaridaki komutu yazip projemiz içerisine Immutable Collection nuget paketi ekledikten sonra Immutable Collectionlari System.Collections.Immutable namespace'i içerisinde bulabiliriz.

System.Collections.Immutable namespace'i içerisindeki tiplere baktigimizda aslinda hepsi bizim günlük development hayatimizda oldukça hasir nesir oldugumuz tipler. Peki bu tiplerin Immutable versiyonlarinda ne gibi bir kullanim farklari var ?

ImmutableList<T>

class Program
{
    static void Main(string[] args)
    {
        ImmutableList<int> integerList = ImmutableList.Create(1, 2, 3, 4, 5);
        ImmutableList<int> newIntegerList = integerList.Add(6);
        Console.WriteLine("Integer List Count:{0}",integerList.Count);
        Console.WriteLine("New Integer List Count:{0}", newIntegerList.Count);
    }
}

Yukaridaki  koda baktigimizda aslinda dikkatimizi çeken 2 önemli nokta var. Bunlardan ilki ImmutableList'i yaratmak için kullandigimiz Create metodu. Create metodunu kullanmamizin ana sebebi Immutable List'i ilk yaratirken efficient bir sekilde sadece 1 kere yaratilmasini saglamak. Yani arka planda sadece 1 collection yaratip sonrasinda da parametre olarak geçtigimiz elemanlari eklemek.

Yukaridaki koddaki bir diger önemli nokta da ImmutableList'in içerisindeki Add metodunun yeni bir ImmutableList döndürmesi. Yani siz elinizdeki ImmutableList içerisine eleman eklemek isterseniz arka planda size otomatik olarak yeni bir collection yaratiliyor ve verdiginiz eleman bu yeni collection içerisine ekleniyor. Ayni durum eleman çikarma veya insert operasyonlari için de geçerli. Peki yukaridaki kodu çalistirirsak nasil bir çiktiyla karsilasiriz ?

ImmutableStack<T>

Immutable Collectionlar içerisinde ilgi çeken tiplerden biri de ImmutableStack tipi. Bu tipi kullanarak Immutable bir sekilde stack yapisi kurabiliyorsunuz.

Örnek olarak,

class Program
{
    static void Main(string[] args)
    {
        ImmutableStack<string> stack = ImmutableStack.Create("Bir""Iki");
        string element = String.Empty;
        var newStack = stack.Pop(out element);
        Console.WriteLine("Element={0}", element);
        Console.WriteLine("Stack Count={0}", stack.Count());
        Console.WriteLine("newStack Count={0}", newStack.Count());
    }
}

Yukarida gördügünüz gibi hizli bir sekilde Immutable bir stack yaratabiliyoruz ve stack içerisindeki Pop metodunu kullanarak en yukaridaki elemani out parameteresi ile elde edebiliyoruz. Out parametresiyle en üstteki elemani alirken ayni zamanda en üstteki elemanin artik içerisinde bulunmadigi yeni bir ImmutableStack nesnesi de metottan geri dönüyor. Yukaridaki kodu çalistirirsak asagidaki sonucu görürüz.

Immutable Collections Mutlaka Bilinmesi Gerekenler

Yukaridaki bölümlerde Immutable Collectionlarin temel çalisma yapisini gördük. Simdi sira geldi Immutable Collectionlarla çalisirken mutlaka bilmemiz gereken noktalara.

  1. Immutable Collectionlarla ilgili bilmemiz gereken en önemli sey Immutable Collectionlari gerektigi zaman ve yerinde kullanmak. Çünkü Immutable Collection kullanmak her zaman diger generic collectionlari kullanmaktan daha iyidir diye birsey yok. Örnegin, diyelim ki bir kütüphane gelistiriyoruz ve kütüphane metotlarindan döndürdügümüz collectionlarin thread-safe olmasini ve içeriginin degistirilemediginden emin olmak istiyoruz. Burada Immutable Collectionlari kullanmak oldukça mantikli ve isimizi kolaylastirmakta. Ancak metot sonucunda Immutable Collection döndürecegiz diye library içerisindeki her yerde Immutable Collection kullanmak dogru degil. Unutmayin ki collectionin durumunu degistirmek istediginizde arka planda yeni bir collection yaratiliyor.
  2. Diyelim ki kütüphaneniz içerisinde kendi ihtiyaçlariniz dogrultusunda generic collectionlari kullandiniz ve artik elinizde bir List<T> tipinden bir  collection var. Bu collectioni otomatik olarak Immutable karsiligina çevirmek için extension metotlari kullanabilirsiniz. (Not : Extension metotlari kullanabilmek için System.Collection.Immutable namespace'ini eklemeniz gerekiyor.)
    using System;
    using System.Collections.Generic;
    using System.Collections.Immutable;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ImmutableCollections
    {
        classProgram
        {
            staticvoid Main(string[] args)
            {
                List<int> integerList = newList<int>();
                ImmutableList<int> immutableList = integerList.ToImmutableList();
                Dictionary<stringstring> dictionary = newDictionary<stringstring>();
                ImmutableDictionary<stringstring> immutableDictionary = dictionary.ToImmutableDictionary();
            }
        }
    }
  3. Eger içerisinde eleman bulunan bir Immutable Collection yaratmak isterseniz ya extension metotlari kullanin ya da Create veya CreateRange metotlarini kullanin. Böylece istediginiz Immutable Collectiondan sadece tek instance yaratmis olursunuz. Örnek olarak asagida farkli 2  kod örnegi bulunmakta. Bunlardan ilki etkin ve daha performansli olarak yeni bir Immutable Collection yaratirken, digeri daha düsük performansli olmakta ve gereksiz yere Immutable Collectionlar yaratmakta. Dogru Kullanim
    classProgram
    {
        staticvoid Main(string[] args)
        {
            ImmutableList<int> immutableIntegerList = ImmutableList.Create(1, 2, 3);
            List<int> integerList = newList<int>() { 1, 2, 4 };
            immutableIntegerList = ImmutableList.CreateRange(integerList);
        }
    }
    Yanlis
    classProgram
    {
        staticvoid Main(string[] args)
        {
            ImmutableList<int> immutableIntegerList = ImmutableList<int>.Empty;
            immutableIntegerList = immutableIntegerList.Add(1);
            immutableIntegerList = immutableIntegerList.Add(2);
            immutableIntegerList = immutableIntegerList.Add(3);
            List<int> integerList = newList<int>() { 1, 2, 4 };
            immutableIntegerList = ImmutableList<int>.Empty;
            foreach (int item in integerList)
            {
                immutableIntegerList = immutableIntegerList.Add(item);
            }
        }
    }
  4. Eger içerisinde hiç eleman bulunmayan Immutable Collectionlar yaratmak isterseniz ilgili class üzerindeki Emptypropertysinden içi bos bir Immutable Collection alabilirsiniz.
    classProgram
    {
        staticvoid Main(string[] args)
        {
            ImmutableList<int> emptyList = ImmutableList<int>.Empty;
            ImmutableDictionary<stringstring> emptyDictionary = ImmutableDictionary<stringstring>.Empty;
            ImmutableQueue<string> emptyQueue = ImmutableQueue<string>.Empty;
        }
    }
  5. Son olarak da Immutable Collectionlarin normal generic collectionlara nazaran daha yavas çalistigini unutmayin. Yavas çalismalarin temel nedeni aslinda implemente edilme sekilleri.  Daha detayli bilgi için burayave buraya bakabilirsiniz.

Immutable Collections'in Gelecegi(Immutable Array)

Immutable Collections paketi release olmadan önce içerisinde ImmutableArray tipini de barindiriyordu. Ancak release olma sürecinde Immutable Array implementasyonu ile ilgili design ve performans sorunlari çikinca bu tip paket içerisinde çikarildi ve bir sonraki versiyona birakildi. Bu nedenle Immutable Collections'in bir sonraki versiyonunda ImmutableArray tipi library içerisine ekleniyor olacak.

Immutable Collectionlar ile ilgili bir yazi yazmak uzun süredir aklimdaydi ancak yeni gerçeklestirebildim. :) Umarim faydali olmustur.



Yorum Gönder