Multiple contribution to different targets

Create issue
Issue #326 new
Idriss Riouak created an issue

If a contributor tries to contribute to two or more different targets, the result of each collection will be the union of all the contribution.

Let us consider the following example:

Root ::= A1:A A2:A B;
A;
B;

and

import java.util.*;
aspect Test {
    inh A B.a1();
    inh A B.a2();
    eq Root.getB().a1() = getA1();
    eq Root.getB().a2() = getA2();

    coll Collection<Integer> A.nbrs() [new ArrayList<Integer>()]
        with add root Root;
    B contributes 1 to A.nbrs() for a1();
    B contributes 2 to A.nbrs() for a2();
}

In this case B will contribute to a1().nbrs() with 1 and to a2().nbrs() with 2. But, after the evaluation of the attributes, we have a1().nbrs() == [1,2] == a2().nbrs().


The problem is due to how the contribution code is generated. Indeed, the generated code for B is the following one:

  protected void contributeTo_A_nbrs(Collection<Integer> collection) {
    super.contributeTo_A_nbrs(collection);
    collection.add(1);
    collection.add(2);
  }

This should be instead (can be improved):

  protected void contributeTo_A_nbrs(Collection<Integer> collection, A node) {
    super.contributeTo_A_nbrs(collection);
    if(node == a1()){
      collection.add(1);
    }else if(node == a2()){
      collection.add(2);
    }
  }

Attached you can find a test case that can be run with the command ./gradlew build

Comments (3)

  1. Jesper Öqvist

    It is not a great solution to evaluate a1() and a2() when adding the contributions, especially if this would happen for all collection attributes. In this particular case, the target attributes have already been evaluated when finding the contribution targets.

  2. Jesper Öqvist

    The workaround for this issue is to use @OnePhase

    @OnePhase coll Collection<Integer> A.nbrs() [new ArrayList<Integer>()];
    

  3. Niklas Fors

    It would be good with another test case that contains when conditions as well:

    B contributes 1 when cond1() to A.nbrs() for a1();
    B contributes 2 when cond2() to A.nbrs() for a1();
    B contributes 3 when cond3() to A.nbrs() for a2();
    B contributes 4 when cond4() to A.nbrs() for a2();
    
    syn boolean B.cond1() = true;
    syn boolean B.cond2() = false;
    syn boolean B.cond3() = true;
    syn boolean B.cond4() = false;
    

    By the way, the current implementation evaluates the when condition (cond1() etc) twice today, once during the survey phase and once during the contribution phase. The suggested solution would do this for the for expression as well. It might be possible with another solution that evaluates both the when and the for expression only once (maybe pass some unique identifier in each contribution statement or using closures).

  4. Log in to comment