Bug 253784 - [itds] Allow super.method() type calls to overridden ITD methods
Summary: [itds] Allow super.method() type calls to overridden ITD methods
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.6.3   Edit
Hardware: All All
: P3 enhancement with 3 votes (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-11-04 16:09 EST by Dave Whittaker CLA
Modified: 2013-06-24 11:04 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dave Whittaker CLA 2008-11-04 16:09:45 EST
Currently, if I have an interface:

public interface ITDInterface{

 public void method();

}

An ITD:

public aspect ITDAspect{

  public void ITDInterface.method(){
    ...do something...
  }

}

And an implementation of ITDInterface, I can not augment the default implementation of method() contained in ITDAspect in a way like:

public void method(){
 
 ..do something first...
 super.method();
 ..do something after..

}

because there is no superclass containing the default implementation, therefore super.method() does not apply, and AspectJ offers no way I can find to invoke methods contained in applied ITDs.

Possible solutions for this would be:

1) Allow a call to super.method() if it can be unambiguously determined that it should result in the invocation of a method defined in an ITD.  In other words, public void method() is defined in only one applied ITD and is not defined within any super type.

2) Allow super type calls only if they are directed specifically to the type referenced by the defining aspect, i.e. ITDInterface.super.method().  This way all invocations would be unambiguous.

3) If this doesn't merit a language feature, provide a utility method for calling the ITD method directly on the aspect like: 

ITDAspect aspect = ITDAspect.aspectOf();
AspectUtils.invoke(aspect, this, ITDInterface.class, "methodName", new Object[]{ param1, param2});

In other words, provide a way to invoke a specific ITD method on the aspect it is defined within, without knowing the naming convention used to generate that method.
Comment 1 Ramnivas Laddad CLA 2008-11-05 12:14:49 EST
Adding discussion from 2001 on the old aspectj mailing list that may serve as a starting point for the feature and possible caveats to consider:

== My initial query ==
Hello,

With AspectJ, a method implementation may be introduced to an 
interface. I have a question related to the way it behaves and 
wondering if it is the right behavior/specification or a bug?

For example, consider:

interface MyIf {
}

class MyClass implements MyIf {
}

aspect IntroduceFooToMyIf {
   public void MyIf.foo() {
       System.out.println("This is MyIf.foo()");
   }
}

This results in a foo() in MyIf and foo() with implementation
in MyClass. So far so good.

Now I change MyClass to:
class MyClass implements MyIf {
   public void foo() {
       System.out.println("This is MyClass.foo()");       
   }
}

This result in not replacing MyClass.foo() by one specified in aspect.
This is ok too because, MyClass.foo() overrides introduced
MyIf.foo().

Now, I change MyClass to:
class MyClass implements MyIf {
   public void foo() {
       super.foo(); // <------- !!!
       System.out.println("This is MyClass.foo()");       
   }
}

I get a compiler error, saying there is no foo() in super (MyIf).
Now, this would be correct from pure Java point-of-view. But
with AspectJ, I expected to result in _equivalent_ of
class MyClass implements MyIf {
   public void foo() {
       System.out.println("This is MyIf.foo()");  <-------
       System.out.println("This is MyClass.foo()");       
   }
}

That is, super.foo() should have been replaced with the introduced
code. In other words, introducing a method in MyIf should have 
behaved as if that method was indeed there.

The replaced code for super.foo() would probably have to be coded 
as a method (just like other code in AspectJ) so that a "return" 
statement in it will not result in an incorrect behavior. But, 
that's just details.

I am interested knowing your opinions.

Thanks and regards.

-Ramnivas

== Jim Hugunin's reply ==

This is a great question.  What it boils down to is whether or not "super.m()" in AspectJ should be allowed to see concrete methods in interfaces or not.  In AspectJ-1.0beta1 the answer is no.  super.m() has exactly the same behavior as in pure Java, and it can only see methods in a super class -- NOT in a super-interface.

<The rest of this message is my personal opinion and not necessarily those of the rest of the AspectJ team.>

I think that you're probably right and that super.m() should be allowed to access concrete methods in interfaces.  However, I don't think that we should add this functionality until after AspectJ-1.0.  Multiple-inheritance is a well-known quagmire of complexity in OO language design, and is something that should be approached carefully.  I'd like to have some calm time to think carefully about any proposal that would expand the power (and the complexity) of AspectJ's current very limited and simple form of multiple-inheritance.  As an example of increasing complexity, if we provide the power you suggest here, I can easily see people asking for qualified super calls to disambiguate multiply inherited methods of the same name, something like "ColorMixin.super.getColor()".

Fortunately, your proposal for increasing the power of super can be added to AspectJ-1.1 or some other future version in a mostly backwards compatible way.  Therefore, my recommendation is that we mostly table this discussion until after AspectJ-1.0.0 is released.

The part that I'd like to talk about today is the mostly-backwards compatible issue.  In order to be able to add this proposal in a completely backwards compatible way to a future version of AspectJ, there is one situation that we are not treating as an error that we should be treating so.  I believe that the following (currently legal in AspectJ-1.0beta1) program should be illegal in AspectJ-1.0:

class SuperC {
  public void m() { ... }
}

interface I {
  aspect BODY {
    public void I.m() { ... }
  }
}

class SubC extends SuperC implements I {
  public void m() {
    super.m();  //ERROR: ambiguous reference to either I.m() or SuperC.m()
  }
}

This change to AspectJ-1.0 would give us the most room to design a clean solution for super and multiple-inheritance at some future time.  It might break some existing AspectJ-1.0beta1 programs; however, I don't believe the odds of that are very high.  If you have existing code or designs that this would break, please let me know.

-Jim

== My follow up ==
Jim,

Thanks for replying.

I think by simply allowing interfaces to have introduced-implemented
-methods, the whole problem of multiple-inheritance is already
opened.

I have two particular problems:
The first one is a practical one. The other is somewhat academic
(assuming it is not common for a class to implemente multiple
interface with a method of exacly same signature), although important 
to consider for the final solution.

1. The situation I was trying to use will not be possible
   (or atleast elegantly possible) unless super.method()
   problem is fixed.

   I have an interface and a default implementation (implemented as
   BODY aspect) of it. In most cases, default is fine. There are,
   however, a few cases where I need to augment the behavior.

   Unless I can call super.method(), such augmentation is not possible.

2. You are right. My next question was going to be about
   possibility of "ColorMixin.super.getColor()" :-)

   Consider for example, 
   public interface A {
       public void foo();
   
       static aspect BODY {
           public void foo() {
               System.out.println("A.foo()");
           }
       }
   }

   public interface B {
       public void foo();

       static aspect BODY {
           public void foo() {
               System.out.println("B.foo()");
           }
       }
   }

   public class AB implements A, B {
       // No foo() implemented here
   }

Current AspectJ implementation chooses to not introduce foo() in
AB at all. Which is fine, considering that it would not be possible
to determine how foo's implemetation should be implemented.

However, I would expect AspectJ to allow adding foo() and let user
choose which implementations to inherit and in what order. 
Something like:
public void foo() {
    A.super.foo();
    // some more code
    B.super.foo();
}

Thanks and regards.

-Ramnivas

== Gregor Kiczales' reponse ==
Aargh!  our goal was to stear clear of as many of the hard multiple
inheritance (MI) issues as possible.  Here's a way of thinking about
the language design that I _think_ can help guide us here.
 
 Our theory about introduction of public methods is that:
 
   - its a rare
   - it should probably only be done when introducing an
     implementation for a well-known interface
 
 In addition, remember that in our language we have advice.
 
 it seems like we can drive our answer to this issue off of 
 these combined facts, and that the answer, at least for now, is
 that we do not support the full case of _multiple_ inheritance.
 We support a weaker thing, which allows a class to get orthogonal
 sets of methods from classes and interfaces.

 I'm less sure about whether we support  overiding of methods inherited
 from an interface.
 
 So if you someone wants to do the additive multiple inheritance thing
 they can use around/before/after.  That means we have less need for the 
 full power of MI. 
 
 I think what I'm saying is that:
 
   - we should signal an error in this case:
 
 > > 
 > > class SuperC {
 > >   public void m() { ... }
 > > }
 > > 
 > > interface I {
 > >   aspect BODY {
 > >     public void I.m() { ... }
 > >   }
 > > }
 > > 
 > > class SubC extends SuperC implements I {
 > >   public void m() {
 > >     super.m();  //ERROR: ambiguous reference to either I.m() or
 > > SuperC.m()
 > >   }
 > > }
 
   - and we could allow super.method() to work in the simple case,
     but we could also prohibit it, at least for now, and point
     people to around.  


Ramnivas, how does this rationale and set of proposed design decisions
fit for you.  Can you use advice the way I mention to get the MI effect
you need?.

== end responses ==
Comment 2 Andrew Clement CLA 2013-06-24 11:04:34 EDT
unsetting the target field which is currently set for something already released