9.8 Inversion of Control
You may sometimes see higher-order functions being discussed within the broader notion of inversion of control. When using higher-order functions, control flow moves from the caller into the callee, which uses function arguments as callbacks into the caller.
To search a list of temperatures for a value greater than 90, you can use the recursive function findGreaterThan90 defined earlier in this chapter, or the loop-based equivalent:
Scala
def findGreaterThan90(list: List[Int]): Option[Int] = var rem = list while rem.nonEmpty do if rem.head > 90 then return Some(rem.head) else rem = rem.tail None
Whether you use recursion or a loop, the list is queried for its values (head and tail), but the flow of control remains within function findGreaterThan90. If instead you use the expression temps.find(greaterThan90), you no longer query the list for its values. Function find is now responsible for the flow of control—and may use recursion or a loop, depending on its own implementation. It makes callbacks to your code, namely the test function greaterThan90.
This shift of control flow from application code into library code is one of the reasons functional programming feels more abstract and declarative compared to imperative programming. However, once higher-order functions are well understood, they become convenient abstractions that can improve productivity and reduce the need for debugging. By using a method like find, you not only save the time it takes to write the three or four lines needed to implement the loop, but more importantly, eliminate the risk of getting it wrong.