Community
Participate
Working Groups
Using declare error : execution((Runnable+).new(..)) && !execution(new(String,..)) I get an extra error, one for constructors with String, and two on those without String. This should not be needed, but avoids the second error: declare error : execution((!Runnable && Runnable+).new(..)) && !execution(new(String,..)) I should only get one message per declare per join point shadow. Find test case in tests/bugs/SubtypeConstructorCW.java, but note that the harness probably ignores duplicate warnings, and so might give a false positive.
Forgot to mention: it looks like the interface constructor (?) is being defined and picked out in each subtype, so this is probably a limitation of the language. Should the constructor be marked synthetic (can constructors be synthetic?).
This either needs clarification of the language spec or a bug fix before 1.2.
This bug reflect a confusion in the 1.1 language design. After discussion with Erik H., the correct design should be, "interfaces should not have constructor execution join points and inter-type constructor declarations on interfaces should not be allowed" Currently there is a huge bug here where we support the syntax for I.new(), but silently ignore the body of the declaration -- we never execute the code and even ignore some compile-time errors that occur therein. We also support a join point for the interface constructor execution that does exist at mostly the correct time. The good thing about this huge bug is that it means no one can be using inter-type constructor declarations on interfaces in an AspectJ program. There might be an extremely small number of people who are depending on the existence of this join point, but I doubt this will be a real problem. Rather than fixing this bug, we should get rid of both. The purpose of inter- type constructors on interfaces was to support initialization better. This can be best accomplished with advice on initialization, i.e. int I.i; I.new(){ i = 2; } goes to int I.i; after(I i) returning: initialization(I) && this(i) { i.i = 2; } This is slightly more verbose, but otherwise is works just as well -- and even better is this actually works. This new behavior is now implemented in the tree and the relevant test passes.