Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Changing this, doc clarification and/or lint WAS: Re: [aspectj-users] Use Cases for Changing target and this in proceed

Just picked up on this thread rather late.

I think at the very least, a documentation clarification is an order. Right now, if I change an argument, or the target of a method call, it has the effect of totally changing that bit of pointcut context in proceed(). If I change this, it has very different and weird effects. As Wes points out, these make sense, but they take quite a bit of hard thinking (and it helps if you have a knowledge of how Java is implemented). E.g. I understand this problem better after reading Jim and Erik's "Advice Weaving" paper than I did the first time I faced it.

I'm also not sure that the utility of Wes's example (given the odd side effects of swapping out this) warrants the existence of such a bizarre mechanism. I agree that it's nicely symmetrical with the other proceed context swaps, so I'd hate to eliminate it. Hmmm. Would a compromise be to issue a lint warning summarizing the side effects if the compiler can determine that "this" might have been reassigned? (With an annotation to suppress the warning if the programmer certifies that he has fully read the AspectJ Necronomicon?)

A simple related language patch might be to allow the following proceed form:

proceed()

even in advice that provides context. It wouldn't help for:

proceed(originalThis, changedArg1, changedArg2)

but it could simplify life for the programmer who just wants to "proceed as planned"

Cheers,

Nicholas Lesiecki
Software Craftsman, specializing in J2EE,
Agile Methods, and aspect-oriented programming
m: 520 591-1849

Books:
* Mastering AspectJ: http://tinyurl.com/66vf
* Java Tools for Extreme Programming: http://tinyurl.com/66vt

Articles on AspectJ:
* http://tinyurl.com/66vu and http://tinyurl.com/66vv
On Dec 13, 2004, at 4:36 PM, Wes Isberg wrote:

Hi -

these seem to be examples of changing the
target object.

Let's say lots of clients use a registry.

If I control (only) the Registry class, then I can change how the
"register(Parm p, ..)" method executes, selecting a strategy based on
whether the moon is full and p is an earth sign.  This advice on
method-execution Registry.register(Parm p,..) means I don't have to
reweave every Registry client to implement my astrological strategy.
(Normally arguments from code-the-compiler-controls are suspect, but
there are semantic equivalents where you'd rather advise execution.)

I'm trying to find a use case where it makes sense to
cause subsequent advice to think that the original client was different

"advice to think...": changing any parameter, this, or target introduces
a potential coherance problem, where other users "expect" something to
happen as a consequence of proceeding with the original object or value. If you change these, it's your responsibility to manage the coherance issues.

The issues do present differently for parameters, target, and this. E.g.,
for method-call join points, method dispatch happens after proceed(..)
whereas in execution join points method-dispatch has happened before any advice is executed. Changing target in proceed(..) of around advice on a method-call join point can change the method executed. Conversely, changing "this" using a subclass instance in proceed(..) in around advice on method
execution does not change the method executed.  Indeed, the superclass
implementation of the method is run even if the subclass overrided that
implementation. (see code below).

But I wonder if a language might use a different form for
proceed where the arguments matched those of the original join point
instead of the parameters of the surrounding advice.

Then one couldn't write one piece of around advice for different {kinds
of} join points.

These are really good questions.  Most OO programmers don't put "this"
on par with some parameter value, and AOP programmers might not consider
carefully things like method dispatch and precedence when considering
the potential interference.  At the very least, replacing "this" raises
issues many developers haven't considered before, and uncovers some of
the complexity in the Java language.  This is another place where I
wish Java supported "const".

Wes

The following code shows:
- replacing "this" in around advice on method execution with a subclass
that overrides the method will *not* result in the overriding subclass method being called. Method dispatch happens before method execution.

- more-precedent after advice is not affected when less-precedent after
  advice changes the "this" parameter.  Thus, it is not simply that the
  value is changed for all subsequent processing, but only for less-
  precedent advice and the original join point.

----- output
Replacing C with D
in C(): D@cac268
after running, this is C@1cde100

----- code - Over.java

public class Over {
  public static void main(String[] args) { new C().run(); }
}
class C {
  public void run() { System.out.println("in C(): " + this); }
}
class D extends C {
  public void run() { System.out.println("in D()" + this); }
}
aspect A {
  pointcut cRunExecution(C c) :
        execution(void C.run()) && this(c) && within(C) ;
  void around(C c) : cRunExecution(c) {
        System.out.println("Replacing C with D");
       proceed(new D());
  }
}
aspect B {
  declare precedence : B, A;
  after (C c) returning : A.cRunExecution(c) {
        System.out.println("after running, this is " + c);
  }
}


------------Original Message------------
From: Curtis Clifton <curt.clifton@xxxxxxx>
To: aspectj-users@xxxxxxxxxxx
Date: Mon, Dec-13-2004 2:31 PM
Subject: Re: [aspectj-users] Use Cases for Changing target and this in proceed

Wes,

Thanks for the quick reply...

On Dec 13, 2004, at 3:31 PM, Wes Isberg wrote:

However, I haven't been able to come up with a
realistic use case for changing the "this" object.

One use is to apply the strategy pattern to a template method.
Another would be to cache a local copy of a remote object; a
variant of this would be to batch updates.  The basic idea is
that there are policies with different behavior or state that
one might want to apply using proxy-like behavior in situations
where you can't manage the references held by the client.

Perhaps I'm being dense, but these seem to be examples of changing the
target object.  I'm trying to find a use case where it makes sense to
cause subsequent advice to think that the original client was different

(neglecting execution point cuts where target and this are confounded).

Do you think this is a case where AspectJ is too powerful? Would the
language be simpler or more complex if you couldn't
replace this or target?

My intuition is that eliminating the ability to change the target
object would sacrifice too much power.  It is fairly easy to come up
with use cases where it is helpful to change the target object.
However, I don't yet understand why one would want to change the "this"

object.

(Warning, the rest of this message gets into speculative language
design questions.  And, lest you think I'm an interloper, please note
that I am not advocating for changes to AspectJ.  I'm just pondering
alternative design decisions.)

Omitting the ability to change this or target without making any other
changes to the language would seem to make the language more complex:
certain parameters to proceed would follow different rules than other
parameters.  But I wonder if a language might use a different form for
proceed where the arguments matched those of the original join point
instead of the parameters of the surrounding advice. The target object

could be changed by prefixing the proceed with "target_expression."
For example:

void around(A tar, int arg) : call(void m(int)) && target(tar) &&
args(arg) {
	new A().proceed(arg * 2);  // equivalent to current AspectJ's
proceed(new A(), arg)
}

This would match the intuition that a proceed is like the original
triggering event for the join point, but with new data.  It also
eliminates the confusion that can arise when two different advice
parameters are bound to the same join point data and the proceed
changes just one of them, as in the following AspectJ code:

void around(A tar1, A tar2) : call(void m()) && target(tar1) &&
target(tar2) {
	proceed(tar1, new A());  // the actual target is the new A, or
generally whichever is right-most
}

In the design I'm pondering that last proceed would be written "new
A().proceed()", eliminating any confusion about the actual target.

There are a variety of issues with the design I'm pondering, including
1) confounding the proceed special form with a call to a method named
proceed, 2) determining the type for proceed when the pointcut doesn't
yield a unique type for the originally called method, and 3) not being
able to change the _this_ object.

I'm trying to understand how big the loss is in issue 3.

Best,

Curt

----------------------------------
Curtis Clifton, PhD Candidate
Dept. of Computer Science, Iowa State University
http://www.cs.iastate.edu/~cclifton

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



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




Back to the top