Tail Call Optimization: Derleyici Rekursiyonu Döngüye Çevirirse Ne Olur?
Recursive fonksiyonlar güzel görünür ama tehlikeli olabilir. Her çağrıda stack'e yeni bir frame eklenir, yeterince derin gidersen stack overflow. Peki derleyici bunu nasıl çözer? Tail Call Optimization (TCO) işte tam burada devreye giriyor.
Bir fonksiyon, son işlemi olarak kendisini çağırıyorsa, bu tail call'dur. Örneğin:
1function factorial(n, acc = 1) {2if (n <= 1) return acc;3return factorial(n - 1, n * acc); // tail call4}Burada `factorial` çağrısı fonksiyonun son işlemi. Derleyici bunu görünce şöyle düşünür: "Bu çağrıdan dönen değeri direk return edeceğim, yeni bir stack frame açmama gerek yok. Mevcut frame'i yeniden kullan."
TCO, tail call'ı bir jump'a dönüştürür. Yeni stack frame açmak yerine, parametreleri günceller ve fonksiyonun başına geri atlar. Sonuç? Stack derinliği sabit kalır. Milyonlarca recursive çağrı yapsan bile, stack overflow olmaz.
Bu dönüşüm optimizasyon seviyesine bağlı. Çoğu C/C++ derleyicisi `-O2` veya `-O3` ile TCO yapar. Scheme ve bazı functional diller bunu garantili olarak yapar, dilsel gereklilik.
Burada işler karışıyor. ES6 spec'i TCO'yu tanımlar, ama sadece strict mode'da ve yalnızca bazı derleyicilerde. V8 (Chrome, Node.js) TCO yapmaz. SpiderMonkey (Firefox) yapar. Safari'nin JavaScriptCore yapar.
Yani aynı kodu Node.js'te çalıştırırsan stack overflow olabilir, Safari'de binlerce çağrı rahatça geçer. Bu dil tasarımcılarının başına bela oldu; web geliştirici bunu bilmediği için production'da sürprizle karşılaşıyor.
Stack frame'i açmamak sadece memory değil, CPU cache'i de etkiliyor. Daha az bellek erişimi, daha az branch misprediction. Ama çoğu durumda fark ölçülebilir değil, kıyasla loop yazmak hala daha hızlı.
TCO'nun asıl değeri correctness'te: stack overflow'dan kurtulmak. Performans bonus.
TCO, derleyici tasarımının zarif bir örneğidir. Ama taşınabilir kod yazmak istiyorsan, TCO'ya güvenme. Fonksiyonel programlamayı seviyorsan, dil seçiminde buna dikkat et. JavaScript'te tail recursion kullanacaksan, Node.js'ten kaçın veya iteratif yaz.
0 yorum