Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-7181

Using a memoized closure with inject corrupts the memoization cache

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Minor
    • Resolution: Fixed
    • 2.3.7
    • 2.3.9, 2.4.0-rc-1
    • 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.

      Attachments

        Activity

          People

            blackdrag Jochen Theodorou
            amordleq Russell Parry
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: