Scala - klasický for cyklus

Scala, na rozdíl od jazyků z rodiny C/C++, nenabízí klasický for cyklus. Podle Martina Oderskyho je příliš imperativní a Scala jako taková tíhne k funkcionálnímu stylu.
Nicméně, to nám nebrání si tuto jazykovou konstrukci doplnit. Tady jsou moje tři pokusné implementace.
// negenerická verze def for0(init: Int, cond: Int => Boolean, incr: Int => Int)(op: Int => Unit) { var i = init; while (cond(i)) { op(i) i = incr(i) } } for0(0, _ < 10, _ + 1) { i => println(i) }
// generická verze 1 def for1[@specialized T](init: T, cond: T => Boolean, incr: T => T)(op: T => Unit) { var i = init; while (cond(i)) { op(i) i = incr(i) } } // typová anotace [Int] je nutná, bez ní kompilátor neodvodí typ fukncí cond a incr for1[Int](0, _ < 10, _ + 1) { i => println(i) }
// generická verze 2 def for2[@specialized T](init: T)(cond: T => Boolean, incr: T => T)(op: T => Unit) { var i = init; while (cond(i)) { op(i) i = incr(i) } } // žádná typová anotace netřeba za cenu jiného zápisu for2(0)(_ < 10, _ + 1) { i => println(i) }
Výsledek bohužel není tak flexibilní jako for cyklus v jazycích, které ho mají v sobě přímo vestavěný.
Scala 3 do hry vnáší klíčové slovo inline
a to zcela mění situaci. Kód
vypadá, chová se a používá se stejně, jen se liší pod kapotou.
inline def for3[T](inline init: T)(inline cond: T => Boolean, inline incr: T => T)(inline op: T => Unit) = { var i = init while (cond(i)) { op(i) i = incr(i) } }
Klíčové slovo inline
znamená, že každé použití funkce for3
bude plně
inlinováno scala kompilátorem. Když pak napíšu následující funkci sčítající
prvky pole, bytekód vypadá identicky, jako kdybych while
smyčku napsal
ručně. Není v něm žádná abstrakce, žádní indirekce, žádné volání anonymních
funkcí, žádná alokace proměnné s
, ke níž se přistupuje z closure, na heapu.
def sum(xs: Array[Double]) = { var s = 0.0 for3(0)(_ < xs.length, _ + 1){ i => s += xs(i) } s }
JVM JIT by udělal podobné optimalizace, inlinoval by vše, co se dá a eliminovat
abstrakce, ale nemusí se mu to vždy povést. Někdy heuristiky selžou, třeba při
příliš hlubokém zanoření. S inline
máme garanci, že se abstrakce zbavíme a kód ke prostá jednoduchá a snadno optimalizovatelná smyčka.