Skip Menu |

This queue is for tickets about the Aspect CPAN distribution.

Report information
The Basics
Id: 63781
Status: resolved
Priority: 0/
Queue: Aspect

People
Owner: Nobody in particular
Requestors: xiaojun.tan [...] picis.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.92
Fixed in: (no value)



Subject: Could not get the return value
The return value is always 'undef' in advice code. When running the attached code (ActiveState Perl 5.8.3), the data dump shows 'return_value' => undef instead of 'James Bond', switching the advice type from afer to after_running to around makes no difference. when uncommented the line $_->proceed in 'around' advice, Aspect complaints "The use of 'proceed' is meaningless in this advice at t3.pl line 7". This is really annoying makes the Aspect virtually useless.
Subject: t3.pl
use Aspect; use Data::Dumper; around { printf "tracing: %s(%s)\n", $_->sub_name, join ', ', @{$_->{'params'}}; ## $_->proceed; printf "\treturn %s\n", $_->return_value; print Dumper($_); } call qr/query_person/; query_person('007'); sub query_person { my ($id) = @_; my $person = 'James Bond'; return $person; }
Subject: Re: [rt.cpan.org #63781] Could not get the return value
Date: Fri, 10 Dec 2010 10:19:05 +1100
To: bug-Aspect [...] rt.cpan.org
From: Adam Kennedy <adamkennedybackup [...] gmail.com>
Firstly, thank you immensely for the bug report. I am utterly shocked that a bug this severe managed to get past what I THOUGHT was extensive testing. As we use this module heavily at my work, I am investigating this bug with utmost priority. I shall have this fixed as soon as possible. Adam K On 10 December 2010 04:21, Xiaojun Tan via RT <bug-Aspect@rt.cpan.org> wrote: Show quoted text
> Thu Dec 09 12:20:59 2010: Request 63781 was acted upon. > Transaction: Ticket created by xtan >       Queue: Aspect >     Subject: Could not get the return value >   Broken in: 0.92 >    Severity: Critical >       Owner: Nobody >  Requestors: xiaojun.tan@picis.com >      Status: new >  Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=63781 > > > > The return value is always 'undef' in advice code. > > When running the attached code (ActiveState Perl 5.8.3), the data dump > shows 'return_value' => undef instead of 'James Bond', switching the > advice type from afer to after_running to around makes no difference. > > when uncommented the line $_->proceed in 'around' advice, Aspect > complaints "The use of 'proceed' is meaningless in this advice at t3.pl > line 7". > > This is really annoying makes the Aspect virtually useless. > >
Thank you once again for your bug report, investigating it has been quite an adventure. The quick answer to your bug report is that Aspect is actually behaving correctly, but that I have done a terrible job of explaining why in the documentation. To understand the long answer, firstly please note that the rewrite of Aspect from the original codebase I took over still has the Aspect::Point tree of modules to go, so there's still a few implementation nigglies in this area. I'll address your problem in two parts. Firstly, the after_returning case. One of the main responsibilities of Aspect is to ensure that regardless of what is done in the advice code, the resulting call to the original function matches as closely as possible the original code. This extends to the list context of the original call. In your bug report, you suggest the following use case. query_person('007'); sub query_person { my ($id) = @_; my $person = 'James Bond'; return $person; } However, this is NOT code that you would ever actually use, as you are calling the function in void context. In practice, you would actually call the following. my $person = query_person('007'); When Aspect calls the original function, it calls it in the same context. So if your call is in scalar context, it ensures that the call to the original function is also in scalar context, and captures the return value. Because you called query_person() in void context, Aspect also called the original function in void context, resulting in no return value, and thus the undef you observed. This is still somewhat wrong behaviour. Ideally it should throw an exception along the lines of "No return_value in void context". But this would mean every single user had to check ->wantarray first before risking a call to ->return_value because you don't control the context you are called in. As a result, I had previously judged it preferable to just have return_value return undef. I may readdress this assumption when I complete the rewrite of the Aspect::Point tree. To summarise, while your example did NOT work, the following WILL work as you expect. use Aspect; use Data::Dumper; after_returning { printf "tracing: %s(%s)\n", $_->sub_name, join ', ', @{$_->{'params'}}; ## $_->proceed; printf "\treturn %s\n", $_->return_value; print Dumper($_); } call qr/query_person/; my $person = query_person('007'); sub query_person { my ($id) = @_; my $person = 'James Bond'; return $person; } Secondly, let me address the around() case. In the original version of Aspect that I took over, the use of proceed was different to the usage of it in the AspectJ toolkit (which I have been trying to broadly mimic where possible). While the AspectJ "proceed" triggers the actual execution of the original code, in Aspect.pm it is used in before() advice as a boolean to indicate "should I proceed after this advice". This is NOT a meaning that makes sense for around() advice, where the triggering of the original function must be immediate. To compensate, the original author created a ->run_original method which achieves the effect you want, plus a ->original access if you absolutely, positively need to call the original code directly without context, param, exception or return_value safety. It was my mistake to show "proceed" in the documentation, as it is my intention to make proceed do what you expect after the Aspect::Point rewrite and I got ahead of myself when writing the documentation. I have corrected the documentation to say "run_original". With regards to your original test case, the following is the final corrected functionality you are plooking for. use Aspect; use Data::Dumper; around { printf "tracing: %s(%s)\n", $_->sub_name, join ', ', @{$_->{'params'}}; $_->run_original; printf "\treturn %s\n", $_->return_value; print Dumper($_); } call qr/query_person/; my $person = query_person('007'); sub query_person { my ($id) = @_; my $person = 'James Bond'; return $person; } To resolve this problem, I have corrected the documentation and in the rewrite (which I hope to achieve over Christmas) I shall change the behaviour of proceed in around() advice to do what you mean, with run_original eventually being deprecated. Best Regards Adam Kennedy