Good to know. But still the `foo`

methods can be easily made tail-recursive by doing a small refactor (intoducing local tail recursive methods).

Call-site `@tailrec`

annotations maybe convey the intent, but you need to understand the whole original idea present in method implementation to not break it. I assume that if you deliberately keep some self recursive calls tail recursive and some non-tail recursive then the tail recursive ones are much more frequent (e.g. by `Theta(lg n)`

times). If someone that refactors the code doesnâ€™t know that then he can destroy that optimization by changing recursive calls frequencies across the self-recursive method.

Example - quicksort with (logarithmically) bounded stack depth:

```
def qsort[T: Ordering](range: Range, array: Array[T]): Unit = {
val pivot = findPivot(range, array)
val (leftRange, rightRange) = partition(range, array, pivot)
if (leftRange.size < rightRange.size) {
qsort(leftRange, array) // non-tail recursion on smaller partition
@tailrec qsort(rightRange, array) // tail recursion on bigger partition
} else {
qsort(rightRange, array) // non-tail recursion on smaller partition
@tailrec qsort(leftRange, array) // tail recursion on bigger partition
}
}
```

Now what if someone refactors the code and inverts the condition in `if (leftRange.size < rightRange.size)`

? `qsort`

stops being stack safe, but is still correct for non-pathological input arrays.