scalapure-function

Scala compiler: detecing a pure/impure function


In FP languages like Scala, Haskell etc. pure functions are used which makes it possible for compiler to optimize the code. For eg:

val x = method1()// a pure function call
val y = method2// another pure function call
val c = method3(x,y)

As method1 and method2 are pure functions and hence evaluations are independent of each other, compiler can parallelize both the calls.

Language like Haskell has constructs within it (like IO monad) which tells whether function is pure or performs some IO operation. But how does Scala compiler detect that a function is pure function?


Solution

  • The general approach to classifying a block of code as pure is to define which operations are pure and since purity composes, a composition of pure operations is pure.

    Parallelization isn't actually one of the more important benefits of pure code: the benefit is that any evaluation strategy can be used. Evaluation can be reordered or results can be cached etc. Parallelization is another evaluation strategy but without a good sense of the actual execution cost (and note that modern CPUs and memory hierarchies can make it really difficult to get such a sense), it often slows things down relative to other strategies. For modern pure code, laziness and caching repeated values is often more generally effective, while parallelism is controlled by the developer (one benefit of pure code is that you can make arbitrary changes to how you're parallelizing without changing the semantics of the code).

    In the case of Scala, the compiler makes no real effort to classify pure/impure code and generally doesn't try alternative evaluation strategies: control of that is left to the programmer (the language helps somewhat by having call-by-name and lazy).

    The JVM's JIT compiler can and does perform some purity analysis on bytecode when deciding what it can safely inline and reorder. This isn't Scala-specific, though final local variables (aka local vals in Scala or final variables in Java) enable some optimizations that can't otherwise be performed. Javascript runtimes (for ScalaJS) can (and really aggressively do, in practice) likewise perform that analysis, as does LLVM (for Scala Native).