Ответ 1
Scala оптимизирует хвостовую рекурсию во время компиляции, как говорили другие плакаты. То есть, рекурсивная функция хвоста преобразуется в цикл компилятором (метод invoke преобразуется в скачок), как видно из трассировки стека при выполнении хвостовой рекурсивной функции.
Попробуйте следующий фрагмент:
def boom(n: Int): Nothing = if(n<=0) throw new Exception else boom(n-1)
boom(10)
и проверьте трассировку стека. Он покажет только один вызов функции boom - поэтому скомпилированный байт-код не является рекурсивным.
Есть предложение, плавающее вокруг реализовать хвостовые вызовы на уровне JVM - что, на мой взгляд, было бы здорово сделать, так как тогда JVM может выполнять оптимизацию во время выполнения, а не просто компилировать оптимизацию времени кода, и, возможно, это означает более гибкую рекурсию хвоста. В принципе, tailcall invoke
будет вести себя точно так же, как обычный метод invoke
, но сбросит стек вызывающего абонента, если это будет безопасно - спецификация состояний JVM, в которых должны храниться фреймы стека, поэтому JIT должен сделать некоторые статический анализ кода, чтобы узнать, не будут ли использоваться фреймы стека.
Текущий статус proto 80%. Я не думаю, что это будет сделано вовремя для Java 7 (invokedynamic
имеет больший приоритет, а реализация почти завершена), но Java 8 может увидеть, что он реализован.