Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Silencing specific warnings when executing coderef?

by LanX (Saint)
on Mar 23, 2014 at 12:56 UTC ( [id://1079437]=perlquestion: print w/replies, xml ) Need Help??

LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

Is it possible to externally disable warnings within the scope of an already compiled code-block?

That is without manipulating $SIG{__WARN__}³ or to deparse and reevalute the code?

Maybe using some B magic?

motivation

I'm playing around to mimic the for LIST -> variables feature of Perl6¹, but with more syntactic sugar, than splice or natatime can provide.

One of my attempts looks like this and kinda works...

implementation:

model:

my @a=1..10; # update2 for (1..3) { from {@a} loop { set my ($a,$b,$c); print "(",$a,$b,$c,")"; # no warnings 'exiting'; # last; }; print "\n"; } __END__ (123)(456)(789)(10) (123)(456)(789)(10) (123)(456)(789)(10)

...but while using loop-control statements like last works (amazing²) it throws a warning which needs to be silenced.

I could refrain to adding new pseudo statements like xlast() but this break in orthogonality would confuse too much.

Manipulating the sig-handler adds to much overhead, using B::Deparse is somehow risky, cause it's not bug-free.

I think this is of general interest for those playing around with syntactic sugar. :)

Cheers Rolf

( addicted to the Perl Programming Language)

update

¹) from perlcabal

This can be extended to take more than one element at a time: Was: while (my($age, $sex, $location) = splice @whatever, 0, 3) + { ... } Now: for @whatever -> $age, $sex, $location { ... } (Except the for version does not destroy the array.)

²) ...and disturbing ... and scaring ... and Perl! ;-)

³) for completeness

$SIG{__WARN__}= sub { return if $_[0] =~ /^Exiting subroutine/; warn $_[0]; };

update2

Put initialization of @a to the start to show that the from-loop reinitializes each time, even if broken with last.

Replies are listed 'Best First'.
Re: Silencing specific warnings when executing coderef?
by tobyink (Canon) on Mar 23, 2014 at 14:23 UTC

    It might be possible in XS, but would require some pretty impressive optree manipulation. $SIG{__WARN__} is the only non-insane way to do it, but as you say, introduces some overhead.

    One "solution" would be to hide the issue. Assuming you intend to export your sugar functions from a module, you can place some code in your module's import method to unimport exiting warning from its caller. Be polite though and document it.

    For what it's worth, even if you can get last to work flawlessly, you'll still have problems with people using @_, caller and return inside the loop body.

    This is the nicest I could get things to work using Parse::Keyword (Perl 5.14+ only)...

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Thanks Toby!

      You are the man to talk to! :)

      Will you come to Sofia?

      > For what it's worth, even if you can get last to work flawlessly, you'll still have problems with people using @_, caller and return inside the loop body.

      • I think @_ can be easily fixed.

      • Dunno if caller is somehow safely overwritable or if the stack can be manipulated. But even if not, I think it's tolerable for a functional construct not to be too transparent.

      • return is certainly a problem

      > For short lists, it's probably slower than yours because it needs to do more set-up before the loop starts.

      Yep but I prefer the flexibility and back-portability of a pure Perl solution before worrying about speed as long as it doesn't exceed factor 10.

      And I'm still fiddling with B::Deparse.

      And as soon as a functional syntax is tested an accepted, it could easily be ported to XS.

      Did you notice that Jesse Luehr's module (thanks for showing, BTW) explicitly warns about using it?

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        Dunno if caller is somehow safely overwritable

        Don't join the too-many developers who have made the mistake of trying to replace caller so that they can hide their magic even more. Code behavior should never depend on caller (that is putting the dependency in the wrong order, despite it being a common trick when loading package-impacting modules like Exporter). So caller should be for debugging on some level.

        The last thing I want is to be lied to when I'm trying to debug a problem (a task that is often complicated already). So modules that overload caller are simply unacceptable to me.

        - tye        

        "Will you come to Sofia?"

        If someone pays me to, sure.

        "Dunno if caller is somehow safely overwritable"

        It can, Sub::Uplevel does this (and documents the caveats).

        "Did you notice that Jesse Luehr's module (thanks for showing, BTW) explicitly warns about using it?"

        It was my bug report that led him to add the warning. The issue can be worked around with PadWalker though, and that's what I do in the section of my example commented Fix Parse::Keyword's handling of closed over variables. I use Parse::Keyword in a few projects, and with a bit of care, PadWalker seems to be able to fix this problem every time.

        The basic problem can be illustrated with this code sample:

        use v5.14; my (@x, @y); for my $i (1..3) { push @x, sub { 1 }; push @y, sub { $i }; } say @x; say @y;

        It will produce output something like this:

        CODE(0x9c3cce8)CODE(0x9c3cce8)CODE(0x9c3cce8) CODE(0x9c2b228)CODE(0x9c2bd08)CODE(0x9c3c9d8)

        You'll notice that @x has the same reference three times, while @y has three different references. This is because at compile-time, when a coderef is encountered, and Perl notices that it closes over a variable, it compiles it into a sort of "proto-coderef". Then when the coderef is hit at run-time (in the example above, the execution of the for loop), Perl sees that it's got a proto-coderef, and fixes up the closed over variables to point to the right data. If the coderef doesn't close over any variables, then it can take the shortcut of reusing the same coderef each time it's encountered at run-time.

        Anyway, the parse_* functions in Parse::Keyword essentially only give you a proto-coderef. If this closes over any lexical variables, you need to do the run-time "point to the right data" bit yourself. So that's what I do in the example.

        If you comment out the PadWalker lines, you'll get warnings about the variables in $x..$y being undefined, this is because without PadWalker the list generation coderef $list is just a proto-coderef compiled before $x and $y have been given any values.

        Anyway, I'm probably boring everybody now. I've just used Parse::Keyword more than most people. Despite its shortcomings, I still think there's life in it.

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Are Pluggable Keywords and Parse::Keyword related?

      FWIW I found a pretty simple way to detect if someone tries to use a return statement within a loop and to warn the author. Parsing the Op-tree with B::Concise shows explicit return ops.

      BUT the concept is flawed cause loops can't be nested since @list is shared by all instances.¹ :(

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      update

      ¹) Think I found an easy way to solve this by accessing the input-array via the caller(1)! :)

        Parse::Keyword is a Perl interface to the XS pluggable keyword API.

        Here's how I look for return and wantarray in Sub::Block (a module which might, by the way be useful for your purposes).

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1079437]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2024-04-25 02:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found