Elixir v1.20 Çıktı: Kademeli Tipli Bir Dil Olma Yolunda!
Elixir geliştirme ekibi, 2022’de set-teorik tipleri Elixir’e ekleme çabasını duyurdu ve Haziran 2023’te Elixir’in tip sistemi tasarımı üzerine ödüllü bir makale yayınladı. Bu çalışma, o zamandan beri araştırmadan geliştirmeye geçiş yaptı. Elixir v1.20 sürümüyle, ilk geliştirme dönüm noktası tamamlandı: tip ek açıklamaları olmaksızın her Elixir programında tip çıkarımı ve kademeli tip denetimi gerçekleştirmek.
Bu, Elixir’in artık ölü kodu ve ‘doğrulanmış hataları’ giderek daha fazla raporladığı anlamına geliyor. Doğrulanmış hatalar, çalışma zamanında yürütülürse başarısız olacağı garanti edilen tip ihlalleridir. Elixir, geliştiriciye ek yük getirmeden ve son derece düşük yanlış pozitif oranıyla mevcut programlardaki doğrulanmış hataları verimli bir şekilde bulabilir.
Bu duyuruda, tip sistemi hedeflerine, Elixir’deki ‘dynamic()’ tipinin ne anlama geldiğine ve ‘doğrulanmış hataları’ nasıl bulduğuna odaklanacağız. Uygulama, ‘If T: Benchmark for Type Narrowing‘ testinde 13 kategorinin 12’sini başarıyla geçerek, sıradan Elixir kodundan hassas tip bilgilerini kurtarabildiğini ve bu bilgiyi dinamik olarak tipli programlardaki doğrulanmış hataları bulmak için kullandığını göstermiştir.
Bu tip sistemi, CNRS ve Remote arasındaki bir ortaklık sayesinde mümkün olmuştur. Geliştirme çalışmaları şu anda Fresha ve Tidewave tarafından desteklenmektedir.
Elixir’de Tipler mi? Tip Sistemi Hedefleri
Elixir’e tanıtılan tip sisteminin ana hedefleri şunlardır:
- Sağlamlık: Tip sistemi tarafından çıkarılan ve atanan tipler, programın davranışıyla uyumlu olmalıdır.
- Kademelilik: Elixir’in tip sistemi, bir değişkenin veya ifadenin tipinin çalışma zamanında kontrol edildiği durumlarda kullanılabilecek ‘dynamic()’ tipini içerir. ‘dynamic()’ kullanılmadığında, Elixir’in tip sistemi statik bir dil gibi davranır.
- Geliştirici Dostu: Tipler, temel küme işlemleri (birleşimler, kesişimler ve negasyonlar) kullanılarak açıklanır, uygulanır ve birleştirilir; bu nedenle küme-teorik bir tip sistemidir ve açık hata mesajları sunar.
Mevcut bir dile tip sistemi eklemek karmaşık bir değişikliktir. Bu nedenle, ilk kilometre taşı, tip ek açıklamaları eklemeden tip sistemini uygulamak ancak yine de ölü kod ve doğrulanmış hataları bularak geliştiricilere değer sağlamaktı. Bu, Elixir’deki diğer kademeli tipli dillerden oldukça farklı olan ‘dynamic()’ tipi aracılığıyla yapılır.
‘dynamic()’ Tipi: Detaylı İnceleme
Çoğu kademeli tip sisteminde, tip sistemi açısından ‘her şey serbest’ anlamına gelen ve tip ihlali rapor edilmeyen ‘any()’ tipi bulunur. Ancak, Elixir’in kademeli tipi ‘dynamic()’ olarak adlandırılır ve iki önemli özelliğe sahiptir: uyumluluk ve daraltma (narrowing).
Uyumluluk Özelliği ve Doğrulanmış Hatalar
Statik tip sistemlerinde, ‘integer() or binary()’ şeklinde bir tipiniz olduğunda ve bir fonksiyon çağırdığınızda, söz konusu fonksiyonun her iki tipi de kabul etmesi gerekir. Ancak, tip sistemleri tüm programların amacını hassasiyetle yakalayamadığından, bu yanlış pozitiflere yol açabilir. Kaynak metinde verilen örneği düşünün: ‘value_or_error’ değişkeni ‘integer() or binary()’ tipine sahip olsa da, ‘/’ operatörü sadece sayıları ve ‘String.upcase’ sadece binary/string’leri kabul etse de program geçerlidir ve çalışma zamanında istisna oluşturmaz. Bir tip sistemi yine de iki ihlal bildirecektir çünkü ‘/’ ve ‘String.upcase’ye sağlanan tipler, kabul edilen tiplerin bir alt tipi değildir.
Elixir’in kademeli tip sistemi, bu tür durumları ele almak için ‘value_or_error’ değişkenini ‘dynamic(integer() or binary())’ tipiyle etiketler. Bu, tipin çalışma zamanında ya ‘integer()’ ya da ‘binary()’ olabileceği anlamına gelir. ‘dynamic()’ tipiyle bir fonksiyon çağrıldığında, Elixir yalnızca sağlanan tipler ve kabul edilen tipler ayrık olduğunda bir tip ihlali yayınlar. Yukarıdaki örnekte, ‘/’ operatörü yalnızca sayı beklese de, ‘dynamic(integer() or binary())’ bir ‘integer()’ olabilir ve kabul edilen ve sağlanan tipler ayrık olmadığından, tip ihlali oluşmaz. Ancak, ‘Map.fetch!’ gibi bir fonksiyon, ‘value_or_error’ yalnızca integer veya binary olabildiğinden harita beklediği için bir ihlal oluşturacaktır. Bu, Elixir’in yalnızca ‘doğrulanmış hataları’ raporlamasını sağlayan uyumluluk özelliğidir.
Daraltma (Narrowing) Özelliği
Elixir’in ‘dynamic()’ tipi aynı zamanda daraltılabilir. Bir değişken ‘dynamic()’ tipiyle başlasa bile, program boyunca kullanıldıkça tip bilgisi rafine edilebilir. Örneğin, ‘data.a + data.b’ ifadesinde ‘data’ değişkeni başlangıçta ‘dynamic()’ olsa da, Elixir onu ‘ %{…, a: number(), b: number()} ‘ tipine daraltır. Bu, eğer ‘data.a + data’ yazılırsa, ‘data’nın önce ‘ %{…, a: number()} ‘ olarak daraltılacağı, ardından ‘number()’ olarak kullanılmaya çalışılacağı ve bu da bir ihlale yol açacağı anlamına gelir.
Özetle, Elixir’deki ‘dynamic()’ tipi, program boyunca kullanıldıkça rafine edilebilen bir aralık gibi çalışır ve tip kontrolleri aralığın dışına düştüğünde ihlalleri rapor eder. Bu, tip bilgisini tamamen reddeden diğer kademeli tip sistemleriyle bir tezat oluşturur. Kullanıcı tarafından sağlanan tip ek açıklamaları tanıtıldığında, ‘dynamic()’ kullanılmadığı sürece Elixir’in tip sistemi statik olarak tipli bir dil gibi davranacaktır. Statik-dinamik sınırı geçildiğinde ise, ek çalışma zamanı kontrollerine ihtiyaç duymadan kademeli tiplendirmenin sağlamlığını sağlayan yeni teknikler geliştirilmiştir.
Tip Koruyucuları, Yan Tümceler ve Daha Fazlası
Bu sürümün arkasındaki çalışmaların çoğu, tip denetimini ve daraltmayı çeşitli yapılarla tanıştırmaktı. Bazı örneklere göz atalım:
- Koruyucular (Guards): Elixir, koruyucularda birleşimleri, kesişimleri ve negasyonları çıkarabilir. Örneğin, ‘when is_list(x) and is_integer(y)’ ifadesi ‘x’in liste, ‘y’nin integer olduğunu doğru bir şekilde çıkarır. ‘when is_map_key(x, :foo)’ ise ‘x’in ‘:foo’ anahtarına sahip bir harita olduğunu (‘%{…, foo: dynamic()}’) çıkarır. ‘when not is_map_key(x, :foo)’ durumunda ‘x’, ‘:foo’ anahtarına sahip olmayan bir harita tipine (‘%{…, foo: not_set()}’) sahip olacaktır.
- Veri Yapısı Boyut Denetimleri: ‘when tuple_size(x) < 3’ gibi ifadelerle, Elixir demetin en fazla iki elemanı olduğunu takip edebilir ve ‘elem(x, 3)’ gibi bir erişim bir tip ihlali oluşturacaktır. Haritalar ve listeler için boyut denetimleri boşluk denetimlerine dönüştürülür.
- ‘case’ ve Koşullu İfadeler: Elixir, sonraki yan tümceleri iyileştirmek için önceki yan tümcelerden gelen bilgileri kullanır. Örneğin, ‘System.get_env("SOME_VAR")’ın ‘nil’ veya ‘binary()’ döndürdüğü bir ‘case’ ifadesinde, ilk yan tümce ‘nil’ ile eşleştiğinde, tip sistemi ‘value’ın artık ‘nil’ olamayacağını ve dolayısıyla yalnızca ‘binary()’ olması gerektiğini bilir. Bu, ölü kodu ve gereksiz yan tümceleri bulmaya da yardımcı olur.
Ayrıca, standart kütüphanedeki demetler ve haritalarla çalışan birçok fonksiyon tiplendirildi. Daha fazla ayrıntı için sürüm notlarına bakabilirsiniz.
Derleme Süresi İyileştirmeleri
Elixir v1.20, özellikle çok çekirdekli makinalarda çalışan uygulamalar için derleme sürelerini bir kez daha iyileştiriyor. BEAM dilleri genellikle verimli derlense de, Elixir’in derleme aracı sentetik testlerde aralarındaki en hızlısı olarak konumlandırılmıştır. Projenize daha fazla örnek ve senaryo ile katkıda bulunmak isterseniz, şeffaf bir karşılaştırma paketi ve sonuçları sağlamak için bir tartışma başlatabilirsiniz.
Ayrıca, modül tanımının ‘:compiled’ (varsayılan) veya ‘:interpreted’ olacağını belirten yeni bir derleyici seçeneği olan ‘:module_definition’ı tanıtıyor. Bu, büyük projelerde derleme sürelerini iyileştirebilir ve diske yazılan ‘.beam’ dosyalarını etkilemez, yalnızca ‘defmodule’ içindeki içeriğin nasıl yürütüldüğünü etkiler. Bunu ‘mix.exs’ dosyanıza ‘elixirc_options: [module_definition: :interpreted]’ ekleyerek etkinleştirebilirsiniz. Daha fazla bilgi için belgeleri okuyun.
Sırada Ne Var?
Önümüzdeki en büyük soru: Elixir, set-teorik tipleri kullanan yeni tip imzalarını ne zaman tanıtacak? ElixirConf EU 2026 açılış konuşmasında tartışıldığı gibi, hala hem araştırma hem de geliştirme çalışmaları var. Tip imzaları ancak aşağıdaki koşullar karşılanırsa tanıtılacaktır:
- Elixir v1.20’deki tip sistemi performansından memnun kalınırsa (ve bu konuda kapsamlı optimizasyon çalışmaları yapılmıştır).
- Özyinelemeli tipler verimli bir şekilde uygulanabilirse.
- Parametrik tipler verimli bir şekilde uygulanabilirse.
- Haritaların anahtar-değer çiftlerini numaralandırılabilir olarak verimli bir şekilde geçmek uygulanabilirse (bu konuda hala araştırma yapılmaktadır).
Bu sorunlar çözüldüğünde, tipli yapı tanımları ve nihayet tip imzaları keşfedilmeye ve tartışılmaya başlanacaktır. Her zamanki gibi, topluluk haberler ve Elixir Forumu aracılığıyla bilgilendirilecektir.
Yayın adaylarını deneyen, karşılaştırmalar yapan ve bize geri bildirimde bulunan herkese minnettarız! Elixir v1.20’yi deneyin ve ücretsiz olarak bulacağı tüm hataları düzeltmeyi unutmayın!

