develooper Front page | perl.perl5.porters | Postings from November 2010

Re: [perl #62412] sqrt without EXPR and Math::Complex always 0

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
November 17, 2010 14:19
Subject:
Re: [perl #62412] sqrt without EXPR and Math::Complex always 0
Message ID:
20101117221921.GS24189@plum.flirble.org
On Mon, Jan 19, 2009 at 03:22:01AM +0100, Abigail wrote:
> On Sun, Jan 18, 2009 at 09:04:16PM -0500, Jarkko Hietaniemi wrote:

> > No eval, true.  But "no warnings 'syntax'", if that's left in I get these:
> > 
> > Prototype mismatch: sub Math::Complex::abs (_) vs none ...

That's a valid warning.

> Ah, I didn't realize that. (I always have 'syntax' warnings disabled).
> 
> But when I enable syntax warnings, I only get the warning if I do:
> 
>     sub hello;
>     BEGIN {
>         set_prototype \&hello, '_' if $] >= 5.010;
>     }
>     sub hello {
>         ...
>     }
> 
> If I set the prototype after the sub has been defined, all seems to be well.

Indeed.


The facetious version:

I have a patch. It removes code (that's always good)
The tests all pass (that's good too):

diff --git a/cpan/Math-Complex/lib/Math/Complex.pm b/cpan/Math-Complex/lib/Math/
index 8475a2b..afec359 100644
--- a/cpan/Math-Complex/lib/Math/Complex.pm
+++ b/cpan/Math-Complex/lib/Math/Complex.pm
@@ -73,20 +73,6 @@ use Scalar::Util qw(set_prototype);
 use warnings;
 no warnings 'syntax';  # To avoid the (_) warnings.

-BEGIN {
-    # For certain functions that we override, in 5.10 or better
-    # we can set a smarter prototype that will handle the lexical $_
-    # (also a 5.10+ feature).
-    if ($] >= 5.010000) {
-        set_prototype \&abs, '_';
-        set_prototype \&cos, '_';
-        set_prototype \&exp, '_';
-        set_prototype \&log, '_';
-        set_prototype \&sin, '_';
-        set_prototype \&sqrt, '_';
-    }
-}
-
 my $i;
 my %LOGN;



The less-than-facetious version:

1: All those calls to set_prototype aren't achieving anything
2: That test can't be testing what it was meant to be testing.

It's necessary to set the prototype *after* the subroutine is defined

Otherwise, it turns out that what happens is:

1: sub is stubbed and has prototype added by the call (in that BEGIN block)
3: parser creates a new subroutine body
3: newATTRSUB assigns that body to the stub, and uses *its* prototype,
   discarding the stub's prototype.

And as the body has no prototype, that (lack of) prototype wins.

Compare:

$ ./perl -Ilib -MScalar::Util=set_prototype -lwe 'BEGIN {set_prototype \&foo, "_"}; print prototype \&foo; sub foo {}'
Prototype mismatch: sub main::foo (_) vs none at -e line 1.
Use of uninitialized value in print at -e line 1.

$ ./perl -Ilib -MScalar::Util=set_prototype -lwe 'sub foo {} BEGIN {set_prototype \&foo, "_"}; print prototype \&foo'
_

I don't have a patch to offer. Moving the BEGIN block later doesn't cause
tests to fail, but that's not filling me with confidence, given that the
tests aren't testing everything that they are meant to be.

(And I'm more interested in why something else I'm trying doesn't quite work,
and curiously this Math::Complex test was the only "test" in core for the
current behaviour of prototypes getting scrubbed)

Nicholas Clark

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About