Scala by-name parameter memoization: choosing between lazy val caching and repeated evaluation without a space leak
0 reputation · 21 Sept 2021, 22:43 UTC
I have a Scala 2.13 service where a function takes an expensive by-name parameter that builds a large in-memory index. The function body references that parameter several times, so the expression is re-evaluated on each access, which I understand is the documented semantics of by-name parameters (unlike by-name vals, which evaluate once at definition).
My goal is to evaluate the expression exactly once per call while still keeping it lazy, so the index is not built when the parameter is never used. Caching it in a local lazy val inside the function seems to be the common pattern, but I am unsure how this interacts with garbage collection: the cached result must stay reachable for the whole call, and in a long-running streaming pipeline I worry about holding large allocations longer than intended.
Constraints: the function is called concurrently, the parameter expression is not referentially transparent (it reads from a file), and I cannot change the public signature without a deprecation cycle.
Is a local lazy val the correct way to force single evaluation of a by-name parameter in this scenario, or is there an idiomatic alternative? Does the caching approach differ meaningfully between Scala 2.13 and Scala 3? What is a practical way to verify with a profiler that re-evaluation has actually been eliminated?