Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Another ITD question

I'd be fine with that if the powers that be don't feel like it would be confusing since the Interface is not really a supertype and the mixed in methods are introduced into the implementing type itself.  If that is a problem, however, what about one of these compromises which don't use "super".

A utility method that allows a user to invoke an ITD method within an aspect without knowing the generated method name, like

ITDAspect aspect = ITDAspect.aspectOf();

AspectUtils.invokeIntroduced(aspect, this, "methodName", new Object[]{ param1, param2});

Or, what I would prefer if it wasn't too difficult would be a new language feature like

ITDAspect.introduced.methodName();

or even as a static method like aspectOf()

ITDAspect.introduced().methodName();

rather than

ITDAspect.super.methodName();

Either way, it would be clear what method was being invoked.  I'm pretty much happy with any feature that allows this behavior though.

Would any of the developers care to weigh in on what type of addition they feel would fit best and how difficult the implementation would be?

Thanks.

-Dave

On Nov 2, 2008, at 2:49 PM, Ramnivas Laddad wrote:

I think, AspectJ should support the super.m() call part of the proposal restricted to situations where the super.m() can be unambiguously deduced. Essentially, the m() method must be *implemented* in only one of the direct parent types (class or interfaces with implementation-introducing aspects). We can leave out the A.super.m() kind of support for now. I believe that will cover the majority of the cases that require augmentative override.

-Ramnivas

On Sat, Nov 1, 2008 at 5:32 PM, Dave Whittaker <dave@xxxxxxxxxx> wrote:
Thanks Ramnivas.  It's good to know that I'm not the only one who is interested in this type of feature.  Since a few years have passed since that thread ended, what are your thoughts on how this could best be accomplished now?


On Oct 31, 2008, at 4:17 PM, Ramnivas Laddad wrote:

Dave, 

I had the same question a long time back, so I am pasting that discussion (obtained from the old list archive at http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/archives/users.zip; I couldn't find a direct link to posts in it on the Internet).

The follow ups have some ideas and flaws with them, should we consider this feature once again.

-Ramnivas

== Orig ==
From ramnivas@xxxxxxxxx  Mon Sep 10 14:14:04 2001
by aspectj.org (8.9.3/8.8.7) with SMTP id OAA10522
for <users@xxxxxxxxxxx>; Mon, 10 Sep 2001 14:14:04 -0700
Received: from web10403.mail.yahoo.com ([216.136.130.95]) by alpha.xerox.com with SMTP id <130077(1)>; Mon, 10 Sep 2001 14:19:22 PDT
Received: from [207.181.251.173] by web10403.mail.yahoo.com via HTTP; Mon, 10 Sep 2001 14:19:22 PDT
Date: Mon, 10 Sep 2001 14:19:22 PDT
From: Ramnivas Laddad <ramnivas@xxxxxxxxx>
Subject: Behavior of super.method() w.r.t. introduced method in an interface
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-BeenThere: users@xxxxxxxxxxx
X-Mailman-Version: 2.0.5
Precedence: bulk
List-Help: <mailto:users-request@xxxxxxxxxxx?subject=help>
List-Post: <mailto:users@xxxxxxxxxxx>
<mailto:users-request@xxxxxxxxxxx?subject=subscribe>
<mailto:users-request@xxxxxxxxxxx?subject=unsubscribe>

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 ==

On Fri, Oct 31, 2008 at 11:27 AM, Dave Whittaker <dave@xxxxxxxxxx> wrote:
I've been using ITDs as a big time saver in defining common actions that can be performed on objects.  This is great in that the default code defined in the aspect applies a majority of the time.  The problem is that in the cases where it doesn't apply, almost every time what I want to do is extend the code defined in the ITD and do something before and/or after the default rather than completely replace it, like a typical object hierarchy would do with a call to super.method(), and I can't find a good way to do that with ITDs.  The best way I've come up with to handle this is to create an abstract superclass from which the interfaces are implemented so the abstract class inherits the default functionality and then in the concrete subclass I can call super.method().

I had posted a similar message a few months ago and someone suggested placing a second method in each ITD interface that would just be used to inherit the default functionality, ie:

public void method();

public void _method();

and then in the ITD _method would define the code and method() would just delegate to _method(), but that just seems like an awful lot of ugly code to perform a simple pattern, which is very anti AspectJ.

So I guess my question is.... is there a better way to do this?  If not, shouldn't their be?  I'd be satisfied with a way to call the method on the aspect, but since it's written out as something like public static void ajc$interMethod$... even if I knew the naming pattern and it wasn't subject to change those calls wouldn't lead to very readable code.  I realize I could also use before/after/around advise on the method but that adds a whole new issue of what order the advice will fire in if the object structure becomes complex.  So has this been an issue for anyone else?  If there isn't a good solution, is there interest from any one else in a new feature to make this type of thing easier?

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users


_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users


_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users


Back to the top