Bug 64069 - ITD name clashes with private members
Summary: ITD name clashes with private members
Status: REOPENED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2   Edit
Hardware: PC Linux
: P5 normal (vote)
Target Milestone: 1.2.1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-05-26 07:08 EDT by Oege de Moor CLA
Modified: 2009-08-30 02:48 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Oege de Moor CLA 2004-05-26 07:08:42 EDT
When weaving into source, ITDs for constructors and methods
override private members of the same signature: it is as if
the private member never existed. This is illustrated
by the example in Dups.java. The same example, when the classes
are compiled separately and using bytecode weaving, gives a
ClassFormatError upon execution. 

The situation for fields is different: the compiler flags an error 
when an ITD tries to introduce a public x where a private x already 
existed. The error is however flagged only when x is used in the
class. Without any uses, such a clashing field is passed by the compiler,
but when the program is run, java throws a ClassFormatError.
This behaviour is illustrated in DupField.java

The above seems to be a bug: the behaviour should
be consistent in all situations.

Request: make it always legal to introduce a new member by ITD that
has the same name/signature as a private member. Mangle the private 
member and all its uses. 

/* ---------------------------------------------------------------
   Dups.java

   When weaving into source, ITDs for constructors and methods
   override private members of the same name. Using bytecode weaving
   (and separate class files for each of the classes) this example
   gives a ClassFormatError upon execution.

*/

aspect Aspect {

    public A.new() { 
       super();
       System.out.println("ITD A()");
    }

    public void A.bar() {
       System.out.println("ITD bar");
   }

}

class A {

    void foo() {
        A a = new A(); 
	bar(); 
    }

    private A() {
	super();
	System.out.println("private A()");
    }

    private void bar() {
	System.out.println("private bar");
    }

}

public class Dups { 

    static public void main(String[] args) {
	new A().foo();
    }
}

/* ------------------------------------------------------------------
   DupField.java
The compiler flags an error when an ITD tries to introduce a public x 
where a private x already existed. The error is however flagged only 
when x is used in the class. Without any uses, such a clashing field 
is passed by the compiler, but when the program is run, java throws 
a ClassFormatError. This behaviour is illustrated in DupField.java:
to see the ClassFormatError, comment out the assignment "x=0" in foo().
*/


aspect Aspect {

    public int A.x;
}

class A {
    private int x;

    void foo() {
        // when the line below is commented, we get a runtime error
	x=0;  // error: The field x is ambiguous
    }
}

public class DupField { 

    static public void main(String[] args) {
	new A();
    }

}
Comment 1 Adrian Colyer CLA 2004-08-09 15:31:27 EDT
marked as target 1.2.1
Comment 2 Adrian Colyer CLA 2004-08-17 06:33:29 EDT
The resolution of this bug will be to give an error message when attempting to 
define an ITD with the same signature as an existing member of the target type. 
(The JLS does not include visibility as part of the signature).

If we did otherwise, consider the situation where a public ITD is made 
over-the-top of a protected member - eurgh!
Comment 3 Adrian Colyer CLA 2004-08-17 07:46:54 EDT
(unless the target type is an interface of course)
Comment 4 Adrian Colyer CLA 2004-08-17 11:42:43 EDT
ok.... we already do the right thing with protected.

The bug report raises an interesting semantic question that the semantics 
appendix doesn't fully address. There is a case to be made that private member 
declarations should not pollute the namespace for external aspects wishing to 
make ITDs on that type (Oege's proposal). This would be equivalent to the 
behaviour seen when declaring a sub-type of the target type. The case for ruling 
that this should be disallowed is that ITDs do not have the semantics of a 
sub-type, but rather the semantics of open class extension (as evidenced by that 
fact that members in the target class are refered to via 'this' within the body 
of an ITDM rather than 'super'). In particular, if the target class defines a 
private method m(), and an aspect makes a public ITDM Target.m(), then a 
reference to this.m() inside the Target class is ambiguous and there is no way 
for the programmer to differentiate between the two possibilities. There's also 
the more obvious point that Java doesn't allow you to define more than one 
member with the same signature but different visibility in the same type - and 
we have said that ITDs have 'same type' semantics rather than 'sub-type' 
semantics. 

All that said, I wasn't party to the original design discussion on how ITDs 
should work in this case.... so ***Erik***, please jump in if you believe that 
we *should* do the mangling thing here....
Comment 5 Adrian Colyer CLA 2004-08-17 11:44:44 EDT
would help if I actually cc'd Erik when asking him a question!
Comment 6 Adrian Colyer CLA 2004-08-18 04:05:21 EDT
With apologies to anyone who is getting fed-up watching me argue with myself....

There's one big disadvantage to the "error message" solution which is this: if I 
write an aspect that makes a public ITD on a target class, that aspect is now 
required to know the internal, private, details of the target class (to make a 
choice of distinct name). Worse, subsequent maintenance (adding or renaming a 
member) of the private members of the target class could break existing aspects. 
That's more tightly coupled than I'd ideally like things to be. If we *did* 
mangle, the rule would have to be that from inside the target type, any private 
member defined in that type hides any ITDs with the same signature.

However, as Andy points out, if we do mangle, it's not just a case of renaming 
the private member and its references, we would also have to ensure that all the 
original (unmangled) join points still exist.

Since the current implementation is broken, we know that no-one is actually 
doing this. I propose to make this an error in 1.2.1, and if we decide that the 
mangling really is the right thing to do, the 1.2.1 behaviour will be described 
as an 'implementation limitation' (as opposed to AspectJ's semantics) and we can 
look to do the harder thing in 1.3.
Comment 7 Adrian Colyer CLA 2004-08-18 08:46:33 EDT
Fix now available for download in latest aspectj development build. Marking bug 
as resolved-LATER pending discussion of whether to do mangling in 1.3 or not.
Comment 8 Erik Hilsdale CLA 2004-08-19 11:35:37 EDT
This is definitely the consistent with the original AspectJ design:  We
consciously decided to make most open-class collisions conflicts, as per 
the Java conflict rules (declaration for methods, reference for fields).  
While Oege is right that it may be a _useful_ mechanism to be able to
have original private members "shadow" inter-type public methods, I'd vote
to have the AspectJ successor language have that feature and leave AspectJ
to not do that shadowing.
Comment 9 Adrian Colyer CLA 2004-10-21 04:32:10 EDT
Fix released as part of AspectJ 1.2.1
Comment 10 Eclipse Webmaster CLA 2009-08-30 02:48:50 EDT
LATER/REMIND bugs are being automatically reopened as P5 because the LATER and REMIND resolutions are deprecated.