Redundant contribution condition test in collection attribute evaluation

Issue #221 resolved
Jesper Öqvist created an issue

JastAdd version: 2.1.11-22-g493d35b

It seems like the contribution condition is evaluated twice when evaluating a collection attribute - once when searching for contributors, and a second time when adding contributions from contributors. This seems redundant. Is it not possible to just evaluate the contribution condition a single time, when searching for contributors?

Comments (3)

  1. Jesper Öqvist reporter

    The reason the extra contribution test exists currently is because many different contributions can exist on the same node for the same attribute, but with different contribution conditions. Perhaps the manual should suggest making contribution conditions lazy?

  2. Jesper Öqvist reporter

    This is related to early/eager condition as described in the collection attribute paper. The @LazyCondition annotation should fix this.

  3. Jesper Öqvist reporter

    Closing this issue because it works as intended. Using cached attributes, or @LazyCondition can improve the performance if condition tests take a long time. However, @LazyCondition is dangerous because it requires that the contribution target can always be evaluated. A benefit of not using @LazyCondition is thus that it is safe. Consider this case:

    import java.util.LinkedList;
    
    aspect Test {
    
      // LazyCondition used for a collection attribute with unsafe lazy condition contributions.
      @LazyCondition
      coll LinkedList<X> R.x();
    
      // Unsafe lazy condition contribution, because the contribution target expression can
      // throw a null pointer exception when the condition is false.
      X contributes this
          when insideA()
          to R.x()
          for enclosingA().r(); // Null pointer exception thrown here.
    
      inh R A.r();
      eq R.getA().r() = this;
    
      inh boolean X.insideA();
      eq A.getChild().insideA() = true;
      eq R.getChild().insideA() = false;
    
      inh A X.enclosingA(); // Can be null!!
      eq A.getChild().enclosingA() = this;
      eq R.getChild().enclosingA() = null;
    }
    

    The above code is obviously bad, but a null pointer exception could be caused by much more innocent-seeming code. The above is part of the test case coll/lazycondition_03f

  4. Log in to comment