Caveats -- Common pitfalls with explanation and solution
Collection.remove seems broken
The following snippet produces an unexpected result:
team class T { protected class R playedBy B {} ArrayList<B> bases= new ArrayList<B>(); void test(R r) { int oldSize= bases.size(); bases.add(r); bases.remove(r); if (oldSize != bases.size()) throw new RuntimeException("WRONG RESULT WILL OCCUR"); } }
Reason: The API of Collection and implementing classes is asymmetric:
boolean add(E e); boolean remove(Object o);
This causes the add invocation to lower (OTJLD §2.2) the argument thus adding the associated B instance to the list. However, remove does not know that the list contains Bs, so it tries to remove the role, which is not found in the list.
This should be seen as a bug in the API of Collection, the OT/J compiler actually behaves as specified.
Workaround: Before invoking Collection.remove on a collection containing base objects while the object to be removed might be passed as a role, it is necessary to assign the role to a variable of the base type to force lowering:
...
void test(R r) {
int oldSize= bases.size();
bases.add(r); // implicitly lowered
B b= r; // force lowering
bases.remove(b);
if (oldSize != bases.size())
throw new RuntimeException("WILL NOT HAPPEN");
}
...Wicked super calls
If a method of a base class contains a super call to a method other than the directly overridden method this can produce unexpected results in conjunction with callin method bindings.
Here is an example of what I call a wicked super call:
public class B0 { void bm() { } } public class B1 extends B0 { void bm2() { super.bm(); // wicked super call } }
In the simplest case the following aspect will not be triggered:
public team class T1 { protected class R playedBy B1 { // note that B0 is not directly affected void rm() { } rm <- after bm; } public static void main(String[] args) { new T1().activate(); new B1().bm2(); } }
Explanation: The wicked super call regards the instance as of type B0, thus the aspect binding for type B1 is not triggered.
Here is a more involved example:
public class B0 { void bm() { } } public class B1 extends B0 { void bm2() { super.bm(); // wicked super call } void bm() { bm2(); } } public team class T { protected class R playedBy B0 { callin void rm() { base.rm(); } rm <- replace bm; } public static void main(String[] args) { new T().activate(); new B1().bm(); } }
Here the OT/J implementation had to choose between two undesirable effects:
- originally the wicked super call invoked aspect dispatch, which, however, includes dynamic dispatch back into B1 thus causing an infinite recursion / StackOverflowError along this circle: B1.bm -call-> B1.bm2 -super call-> B0.bm -dynamic dispatch-> B1.bm.
- as of r19093 this recursion is fixed (see also #146), but now the wicked super call does no longer trigger the aspect although role R is in this case actually bound to the base class B0.
The latter behavior is a bug, but within the current weaving strategy no simple solution is available for fixing the bug without the mentioned danger of a StackOverflowError.
Workaround: Should you encounter the situation (2.) please try to find another join point that is not a wicked super call.
all news
RSS feed