Bug 70794 - The introduction on interface causes the interface implementation class error
Summary: The introduction on interface causes the interface implementation class error
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 1.2.1   Edit
Assignee: Andrew Clement CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-07-25 16:53 EDT by Dapeng Gao CLA
Modified: 2004-10-21 04:32 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dapeng Gao CLA 2004-07-25 16:53:43 EDT
The following is an simple example, whcih shows the bug. If using eclipse and
AJDT to compile, it will generate an error messge, saying world method must be
implemented.

public interface hello {
	//empty interface
}


//aspectj introduce a method to this interface
public privileged aspect aspectWorld {
	abstract void hello.world();

}

//class test implements hello interface, and
//method world
public class test implements hello{
    
	public void world(){
		 System.out.println("hello");
	}
	
	public static void main(String[] args) {
		test t = new test();
		t.world();
	}
}
Comment 1 Mik Kersten CLA 2004-07-26 13:51:17 EDT
You're introducing an abstract method on an interface, and then extending that 
interface without providing an implementation.  So it seems that the compiler 
is behaving correctly, asking you to provide an implementation to that method, 
as it would if you had declared the method on the interface itself.

Please explain if this is not the behavior that you are expecting 
Comment 2 Dapeng Gao CLA 2004-07-26 15:37:16 EDT
In class test, I provided the implementation for the world method. Therefore,
test class already have the implementation, it shouldn't generate error message. 

If I move the world method to hello interface from the aspect class (comment it
out from the aspect class), the sample code will be compiled. 

I feel the behavior of the code with aspectj should be same as the second case,
but in the first case, the aspectj compiler has compilation error.

Comment 3 Mik Kersten CLA 2004-07-26 19:21:59 EDT
Declaring an abstract method on an interface is not an idiom that I have seen 
before.  Using an inner aspect to achieve this is more typical, since it puts 
all of the crosscutting into one place (both the inter-type declaration and 
the implementation).  E.g. for your code

public class test implements hello {
    static aspect WorldImpl {
        public void hello.world() { // hello is an interface
            System.out.println("hello");
	}
    }
    ...
}

Nevertheless, we will need to add Programming Guide documentation for your 
case, and either produce a better error message for why it doesn't work or 
list it as a limitation.  It will also need test coverage added.

Andy: I'm reassinging compiler-related bugs to you for now, let me know if I 
should be giving them to someone else.
Comment 4 Andrew Clement CLA 2004-08-02 13:32:19 EDT
The reason this is not compiling is that the declaration from the aspect:

abstract void hello.world()

is not public.  This means AspectJ puts something clever in the interface (it
does *not* 'auto promote' the declaration to public visibility).  If you change
the aspect to:

public privileged aspect aspectWorld {
  public abstract void hello.world();
}

then the program compiles just fine.

The fact that the declaration hasn't been promoted to public like it would have
been if declared directly in the interface requires either:

1) Fixing (if the target for an ITD is an interface, we could force it public if
it is default visibility)
2) An xlint warning to tell you there are going to be problems because of the
visibility.

This is discussed in depth in bug 49784.
Comment 5 Andrew Clement CLA 2004-08-12 08:37:29 EDT
I've had an email exchange with Erik over this bug, which is worth including
here.  It discusses the various cases for the visibility of the interface and
the visibility of the abstract method ITD'd upon it:

---
The meaning of the example depends crucially on two things:  whether the
abstract inter-type declaration is public, and whether the interface target
is public.  Here are the cases:

(public I) x (public abstract void I.foo() )

   This is fine.  I assume this works now, and we just inject an abstract
declaration named "foo".  

(package I) x (public abstract void I.foo() )

   Same as above.

(package I) x (package abstract void I.foo() )

   This is meaningful:  We're adding a constraint on all implementors of
this interface that they include an (at least package-level) implementation
of foo.  This is also implementable, assuming that we get the whole package
in our compilation unit, incremental or no (I'm pretty sure we rely on that
assumption elsewhere).  The weaver must inject a method   
    public void ajc$interMethodDispatch2$$foo() { this.foo(); }
to every direct implementor of I in the package.  I'm pretty sure that's why
we're generating the mangled method in the interface, we just forgot to
inject the dispatch method.  Oops...

    Note that I haven't provided a use-case here... I'm pretty sure this is
of very limited usefulness, if at all.  But I don't _think_ it's too hard to
implement...

(public I) x (package abstract void I.foo() )

   This is NOT MEANINGFUL, and we should signal an error here.  The intent
is that we're adding a non-public constraint to all package-level
implementors of I.  That's all well and good, but it violates the whole
reason for using a public interface.  If we have something typed to I inside
of our package, we have no idea whether it's one of "our" I's, with a
definition of foo(), or one of some other package's I's, with no such
definition.  (We could do a weird runtime thing here, but I can't bring
myself to describe the horribleness.  Feel free to ask if you care).
Anyway, the compiler should definitely just flag this as an error.
Comment 6 Andrew Clement CLA 2004-08-12 09:42:59 EDT
Per Eriks description, I have implemented case (4):

(public I) x (package abstract void I.foo() )

will cause an error now - and this would have picked up the testcase for which
this bug was raised.

The problem is case (3):

(package I) x (package abstract void I.foo() )

I can probably get it to work (as he says, we don't currently generate the
dispatcher method).  My concern is that the version of I that is spat out at the
end looks like this:

interface I {
  public abstract void ajc$interMethodDispatch2$$foo();
}

So we have added a public dispatcher method to the interface.  I'm still
thinking about whether this is a problem...
Comment 7 Andrew Clement CLA 2004-08-18 11:13:56 EDT
Adrian and I have been discussing this.  We are leaning towards this rule:

If you make an *abstract* inter-type declaration and the target is an interface,
then your ITD must be declared public.  If you haven't specified public we will
put out an error message.

This will help us get round the issue discussed here and in bug 49784 where, if
you build the interface with the non-public abstract ITD against it into a class
file and then sometime later attempt to provide an implementation using the
ITD'd form of the interface as binary input to the compile, you get a misleading
error like the one reported here.

comments?
Comment 8 Andrew Clement CLA 2004-08-20 09:35:27 EDT
Fix checked in as discussed yesterday.  It is a compiler limitation.  The rule is:

"An abstract ITDM on an interface must be declared public."

I like straightforward rules like that.

We can revisit the limitation in future if anyone ever comes up with a suitable
use case for supporting non-public abstract ITDMs.
Comment 9 Andrew Clement CLA 2004-08-23 03:15:51 EDT
Fix available:

BUILD COMPLETE -  build.350
Date of build: 08/20/2004 15:02:32
Time to build: 99 minutes 15 seconds
Last changed: 08/20/2004 14:31:09
Latest good AspectJ jar available at:
download.eclipse.org/technology/ajdt/dev/aspectj-DEVELOPMENT.jar

We now police ITDs that can get you into this situation and put out an error
message.  Here is the error for the example code in this bug:

C:\temp\hello.java:14 [error] abstract intertype method declaration 'void
hello.world()' on interface hello must be declared public (compiler limitation)
class test implements hello{
      ^^^
	see also: C:\temp\hello.java:8

1 error
Comment 10 Erik Hilsdale CLA 2004-08-23 20:04:45 EDT
Note that I've also inserted the following into the semantics guide, to take
care of the fact that non-public abstract onto public interface is a language
error, not just a compiler error.  The verbiage is obtuse, as usual.

        The access modifier of abstract inter-type methods has
        one constraint: It is illegal to declare an abstract
        non-public inter-type method on a public interface.  This
        is illegal because it would say that a public interface
        has a constraint that only non-public implementors must
        fulfill.  This would not be compatible with Java's type
        system.  
Comment 11 Adrian Colyer CLA 2004-10-21 04:32:43 EDT
Fix released as part of AspectJ 1.2.1