Details
-
Bug
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
2.3.7
-
None
-
None
Description
A memoized closure cannot be used in an inject call without causing problems with the memoization cache.
Here is a contrived example that demonstrates the problem:
int maxExecutionCount = 0 Closure max = { int a, int b -> maxExecutionCount++ return Math.max(a,b) }.memoize() int minExecutionCount = 0 Closure min = { int a, int b -> minExecutionCount++ return Math.min(a,b) }.memoize() 100.times { max.call(max.call(1,2), 3) } 100.times { [1,2,3].inject(min) } assert maxExecutionCount == 2 assert minExecutionCount == 2
The second assert fails with an actual minExecutionCount of 101.
I believe what's happening is that inject uses a single argument array and modifies the elements of the array as it iterates over the list. The argument array used to call a method becomes the key in the memoization cache, so modifying it after the call causes the key to change after it has been put into the cache. Nothing can ever find this key, since its equals() is no longer consistent with the hashCode() that was used to put the key in the cache.
In case of an org.codehaus.groovy.runtime.memoize.UnlimitedConcurrentCache the cache will grow forever. In the case of ...LRUCache the cache will be thrashed with any new inject calls.