Bug 42743 - declare soft limitation
Summary: declare soft limitation
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.1.0   Edit
Hardware: PC Windows XP
: P4 enhancement (vote)
Target Milestone: 1.2.1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-09-08 23:13 EDT by Ron Bodkin CLA
Modified: 2005-08-13 16:29 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 Ron Bodkin CLA 2003-09-08 23:13:30 EDT
This code compiles properly under AspectJ 1.0.6, but it fails under 1.1.0 and 
under cvs head as of 9/8/03:

C:\eclipse\workspace\atrack>ajc src\SampleExceptionHandling.java
C:\eclipse\workspace\atrack\src\SampleExceptionHandling.java:3 exact type 
patter
n required

1 error

// Copyright (c) 2003 New Aspects of Security. All Rights Reserved.
public aspect SampleExceptionHandling {
    declare soft: (Exception+ && !RuntimeException+): within(com.example..*);
}
Comment 1 Ron Bodkin CLA 2003-09-09 13:10:40 EDT
contributing the source per CPL:

/** @author Ron Bodkin */
public aspect SampleExceptionHandling {
    declare soft: (Exception+ && !RuntimeException+): within(com.example..*);
}
Comment 2 Jim Hugunin CLA 2003-09-09 13:15:37 EDT
This is a change that was made for the 1.1.0 implementation and documented in
the release notes, i.e.

'declare soft: TYPE: POINTCUT;' - AspectJ 1.1 only accepts TYPE rather than a
TYPE_PATTERN. This limitation makes declare soft much easier to implement
efficiently. (CTI)

This issue is more serious than it sounds from the brief description in the
release notes and any proposal to expand declare soft to take a TYPE_PATTERN
again in 1.2 will have to include a compiler patch demonstrating how it might be
implemented.

Personally, I think that the main question here is how unchecked exceptions
should interact with declare soft.  Maybe we need a different form of declare
soft that won't ever wrap unchecked exceptions...

I'm leaving this as a P4 enhancement request to be rediscussed for 1.2.
Comment 3 Ron Bodkin CLA 2003-09-09 13:32:07 EDT
I agree, the major issue that I want to address is only converting checked 
exceptions, not RuntimeExceptions. This _can_ be done, albeit less 
efficiently, by recovering the original RuntimeException in around advice that 
catches the SoftException.

Another enhancement that would fix this and other useful idioms would be 
supporting defined type patterns, rather like declare parents except this 
would be tracked only at compile time, but could also include classes that the 
compiler doesn't control. I realize that this would be a major crosscutting 
change.

I did look at the release notes, but stopped reading after the list of changes 
for bytecode weaving (obviously I skimmed too fast). Interestingly the 
compiler accepts Exception+ silently; using a pattern like that is worth a 
warning.
Comment 4 Nicholas Lesiecki CLA 2004-08-01 21:45:25 EDT
I just want to note that this issue was not fixed in AspectJ 1.2, and still severely limits the usefulness of 
declare soft. I don't think that it's necessary that declare soft accept a type pattern. I would be 
comfortable if it implicitly softened only checked exceptions. 

As Ron notes, there's a workaround. However, it shouldn't be necessary to use a workaround for the 
most generic use case of a language feature. Is there any chance this issue can make it into a point 
release of AspectJ 1.2? AFAICT changing the behavior of the feature should have minimal impact on 
existing code. The only problem I can forsee would be client code expecting (i.e. catching) 
SoftException that was supposed to have wrapped a RuntimeException.
Comment 5 Adrian Colyer CLA 2004-08-10 04:29:02 EDT
re-opening the debate on this for 1.2.1.
Comment 6 Nicholas Lesiecki CLA 2004-08-17 01:02:20 EDT
Is there any debate to be had? Or are you just reopening with a target of 1.2.1?
Comment 7 Adrian Colyer CLA 2004-08-17 05:27:01 EDT
Yes, I think there is - or at least some education on my part. The change I'm 
prepared to consider is making declare soft NOT soften runtime exceptions, but I 
want to really understand the strong use cases for this before we do it. The 
reason that this needs to be carefully justified is that it changes the 
semantics of the language (and in a point release) in a way that may produce 
unexpected runtime failures (much worse than getting new compilation errors or 
warnings on upgrading). The nightmare scenario is someone using declare soft to 
deliberately soften runtime exceptions, and then catching a SoftException 
somewhere and expecting it to handle *all* cases. If we make the change, this 
program will still compile happily, but an NPE say would slip under the radar of 
their exception handling.

The counter-argument is that we are adding new aspectj users all the time, so if 
we think this is the right thing to do, it is better to do it sooner rather than 
later.

So, I'd like to understand why you both believe that 'the usefulness of declare 
soft is severely limited' as it is. I always imagined declare soft being used in 
conjunction with advice. So you write some advice that deals with an exception 
condition at a given set of join points (after throwing for mapping into domain 
exceptions, around advice if you are genuinely going to handle), and once that 
advice is in place you say to the compiler "OK, I've got an exception handling 
policy in place, so please don't complain about needing to handle checked 
exceptions at these join points". I'm sure I recall from earlier discussions on 
this topic that this was Jim's opinion too. When used like this, there won't be 
any logic in your application that is working with SoftExceptions at all. (And 
yes, when you read that sentence it seems logical that declare soft would not 
soften unchecked exceptions  - but it does today, so we need a strong enough 
case to change the status quo).

When you use declare soft in conjunction with advice then, that just leaves the 
case where you write something like:

after() throwing(Exception ex) : pc() {
  if (ex instanceof RuntimeException) {
    throw ex;
  } else {
    throw new DomainException(ex);
  }
}

The nuisance here is that the RuntimeException you wanted to throw from the 
advice will get softened. 

BUT - is this a useful use case that justifies the change? If you're mapping to 
domain exceptions, why would you not also convert runtime exceptions? And if you 
don't want runtime exceptions, why ask for them in the advice spec.? For 
example, if you write:

try {...}
catch(Exception ex) {...}

you'd better be prepared to handle what comes your way. Likewise if you write 
after throwing or declare soft against just "exception". It's a much better 
practice to catch the exceptions you actually want isn't it?? Another reason not 
to change is that the semantics are currently 'instanceof' (declare soft softens 
any instanceof the given exception) which is very clear and already 
well-understood by Java programmers.

So, I've set before the jury the case for leaving the implementation as-is. Can 
we now hear the evidence in favour of the change? ;)
Comment 8 Adrian Colyer CLA 2004-09-08 08:16:05 EDT
Ron, Nick - a last call before I shut the door on this. I made the case for 
*not* implementing this change in my last append, and am waiting for you to make 
a stronger case in favor of the change. If there isn't one, then I propose to 
close out the enhancement request, but if there is, I'm still prepared to 
listen...
Comment 9 Ron Bodkin CLA 2004-09-08 18:11:00 EDT
I do think this change is quite important. One of the biggest issues I have with
the current approach is that it doesn't let me implement a policy of handling an
exception once by converting it to an unchecked domain exception efficiently or
modularly. I.e., I am of the school of thought that domain exceptions should be
unchecked, so their handling isn't scattered and tangled across layers of code
that don't need to be involved in their handling. Consider the aTrack code for
exception handling below. Because we want to soften any exception that internal
methods throw and convert to domain exceptions, we are forced to keep softening
and re-converting them at every method until the exception is eventually
handled. This type of exception policy is quite popular and useful (I've seen
applications where it was literally implemented manually with try-catch in every
method). So I think the value of supporting it far outweighs the cost of making
a small backward compatibility change. If you want AJC 1.0.6 behavior you just use:

after() throwing (RuntimeException e) : somePointcut() {
    throw new SoftException(e);
}

Sample code follows:


I'd venture to say that as it's currently implemented, declare soft is only
usable for narrowly defined categories of exceptions with a common base type. I
think that's a shame; there are definitely cases you'd like to 

public abstract aspect ExceptionHandling {
...
    private pointcut exceptionConversionPoint():
        (StandardPointcuts.anyExec() || staticinitialization(*)) && inScope(); 

    /** define where to soften checked exceptions */
    //we really need a declare soft for !RuntimeException ...
    //we do NOT want to keep rethrowing SoftExceptions 
    declare soft: Exception: exceptionConversionPoint();

    after() throwing(Exception  e) : exceptionConversionPoint() {
        Throwable t = e;
        while (t instanceof SoftException) {
            t = ((SoftException)t).getWrappedThrowable();
        }
        if (!(t instanceof AtrackException)) {
            Log log = getLogger();
            if (log.isWarnEnabled()) { 
                log.warn("converted exception at "+thisJoinPointStaticPart, e);
               
log.warn(AtrackExecutionTracer.aspectOf().getJPContextStr(thisJoinPoint)); 
            }
            throw convert(e);
        } else {
            throw (AtrackException)t;
        }
    }

    protected RuntimeException convert(Throwable t) {
        ...
    }
}

seen with the current behavior is exactly the problem of softening checked
exceptions. If one has a policy that 
Comment 10 Ron Bodkin CLA 2004-09-10 01:10:52 EDT
I should have said AJC 1.2 and earlier code, not AJC 1.0.6. Let me know if you 
want references to some articles that argue for using unchecked exceptions for 
applications. In practice, everyone in the Java world makes these extend 
RuntimeException and _not_ Error, so it would be a shame to not support 
policies that soften checked exceptions and convert them to user-defined 
subclasses of RuntimeException.

Long term, I'd like to see a declare throws form for AspectJ, which would 
allow using checked exceptions for interface methods without scattering and 
tangling them throughout the system.
Comment 11 Adrian Colyer CLA 2005-03-13 21:23:25 EST
I implemented this change on the plane on the way across to Chicago. declare
soft now no longer softens RuntimeExceptions. The change is described in the
AJDK Developer's Notebook under the 'miscellaneous' heading:
http://dev.eclipse.org/viewcvs/index.cgi/org.aspectj/modules/docs/adk15ProgGuideDB/miscellaneous.xml?rev=HEAD&content-type=text/vnd.viewcvs-markup&cvsroot=Technology_Project

Fix now in CVS HEAD.
Will close this bug report once the fix is available in a published build.
Comment 12 Adrian Colyer CLA 2005-08-13 16:29:19 EDT
Should have been closed off as fixed a long time ago.....