Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Potential Ternary Operator Bug

by davorg (Chancellor)
on Dec 10, 2001 at 20:36 UTC ( #130696=perlquestion: print w/replies, xml ) Need Help??

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

This just came up in the CB. Someone wanted to filter an array into two arrays. I decided to be clever and suggested this:

push @{ ($_ % 2) ? @odd : @even }, $_ foreach @numbers;

That works as expected, but it turned out that the filtering should be done on a regex match. I changed my code to:

push @{ (/PAT/) ? @match : @nonmatch }, $_ foreach @words;

But that gives a "Bizarre copy of ARRAY in leave" error. Changing it again to:

push @{ (/PAT/) ? \@match : \@nonmatch }, $_ foreach @words;

gets it working again. And on reflection, that's what should work. So, I guess the original version shouldn't work (you should need to take references in that case as well). But it does. Any explaination?


"The first rule of Perl club is you do not talk about Perl club."
-- Chip Salzenberg

Replies are listed 'Best First'.
Re: Potential Ternary Operator Bug
by merlyn (Sage) on Dec 10, 2001 at 21:13 UTC
    My hunch is that this "works" in the same way that @a->[3] "works", in that an array name is sometimes automatically a reference to that array, even though the language definition would argue otherwise. I've heard it would take deep voodoo to get the current interpreter to have the right info to reject that, so we'll have to wait until perl 6, where it'll be blessed instead of cursed. {grin}

    -- Randal L. Schwartz, Perl hacker

      It's actually very easy to get the interpreter to reject @a->[3] - I'm not sure how the rumour that it's hard began. I wrote a very simple patch, which is in bleadperl, to deprecate that usage:

      [robin@penderel perl@12959]$ ./perl -we '@x->[2]'
      Using an array as a reference is deprecated at -e line 1.

Re: Potential Ternary Operator Bug
by chipmunk (Parson) on Dec 10, 2001 at 23:24 UTC
    Actually, this bug isn't really related to the ternary operator. The bug is with using array derefencing on an array rather than a reference to an array.
    perl -e '@{ $_; @_ } = 1' Bizarre copy of ARRAY in leave at - line 1.
    Note that this code: perl -e '@{ @_ } = 1' does not produce the error. However, it does produce the error when run in the debugger.

    I expect it's something to do with the state of the stack after the contents of @{ } are evaluated. I can't explain why it works in some cases (even though it shouldn't) and not in others. :)

All code blocks are not created equal: HINT_BLOCK_SCOPE
by chip (Curate) on Dec 11, 2001 at 02:44 UTC
    The difference you're seeing is due to the complexity (or lack thereof) of the expression in the @{}.

    Simple bits of code that can't possibly have local state to unwind or exception handling to perform will work in your test case. That's why the modulo test is OK. (Mind you, its working is an undocumented and unreliable accident, but this being the Monastery I'm not stopping with RTFM.)

    More complex bits of code that may have local state to be unwound trigger Perl to make copies of their results when they exit. Classic examples of such expressions are user subroutines and the do BLOCK construct, but they can also arise in other circumstances. Since pattern matches can do really weird and complex things, putting a regex in your array reference expression forces the final result of the expression to be copied ... and that's what leads to the "bizarre copy" message.

    The fact that Perl makes this distinction is the basis of an important optimization: Introducing what looks like a code block doesn't necessarily impose the overhead of a code block. The overhead is imposed only if something that looks dangerous or complex appears inside the given block.

    For further info on this phenomenon, grep the Perl source code for the constant HINT_BLOCK_SCOPE.

    PS: The fact that do BLOCK forces copies is exactly the reason why do { local *FH } makes an anonymous glob value every time it's evaluated.

        -- Chip Salzenberg, Free-Floating Agent of Chaos

Re: Potential Ternary Operator Bug
by chromatic (Archbishop) on Dec 11, 2001 at 02:30 UTC
    I agree with merlyn, having found that error deep in the bowels of sv.c. That's the bit of Perl that handles all things scalar. It's all in the sv_setsv_flags function, which copies one scalar to another. If the source scalar is actually a pointer to an array, hash, sub, or filehandle and if there's an opcode attached (that is, if PL_op exists), it'll throw this message.

    If you deparse it with B::Terse, you'll find that the second op under the assign opcode is rv2av, dereferencing an array reference. Next up are a couple of leave/enter block opcodes. That's where the 'in leave' comes from. Looks like this prevents a core dump. Weird.

    Anything else, you'll have to find someone who knows better than I.

Re: Potential Ternary Operator Bug
by blakem (Monsignor) on Dec 11, 2001 at 00:38 UTC
    Interestingly enough, taint-checking will make your first example to throw that error as well....
    % perl -Te 'push @{ ($_ % 2) ? @odd : @even }, $_ for 1..20' Bizarre copy of ARRAY in leave at -e line 1. % perl -e 'push @{ ($_ % 2) ? @odd : @even }, $_ for 1..20' [no error.....]


Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://130696]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2022-01-28 22:40 GMT
Find Nodes?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:

    Results (74 votes). Check out past polls.