in reply to Re^2: File::Temp survival and scope created by "do"
in thread File::Temp survival and scope created by "do"

Well it looks like the variable $x (ie, the name) is only visible inside the do BLOCK, but the associated scalar's life is bound to the containing scope.

I'm not sure what you mean about being able to return a value, but having the inverting the order of the statements inside the do BLOCK yields the same result:

perl -le "sub Foo::DESTROY {print 'BLAM'}; print 'A'; do { 1; my $x = +bless {}, 'Foo' }; print 'B' "; A BLAM B
(yup, windows over here). This looks like an optimization issue, when do contains only a single statement, I guess it is optimized as a single statement executed in the containing scope, while the visibility of the variable is still limited to the do block.

The fact that it works properly when the do contains more than one statement means there isn't a real problem though, because if there's only one statement, the lexical declaration is technically not needed. (Edit: Or maybe the issue is that perl lets you declare a lexical that you never use, but that's not specific to do)

Replies are listed 'Best First'.
Re^4: File::Temp survival and scope created by "do"
by haukex (Archbishop) on Dec 10, 2018 at 20:42 UTC

    Interesting, thanks for looking into it further!

    I'm not sure what you mean about being able to return a value

    I mean that in e.g. my $x = do { my $y = "foo" }, $x is assigned the return value of the assignment ("foo") - you can't do things like for example my $x = do { if (/x/) { "X" } else { "_" } } with a bare { BLOCK }.

    This looks like an optimization issue, when do contains only a single statement, I guess it is optimized as a single statement executed in the containing scope

    You may be onto something, there are some differences in the following two, although I don't know enough about the internals to say if the differences are relevant to the issue. I do think do { EXPR } shouldn't be optimized to just EXPR...

    $ perl -MO=Concise -e 'sub DESTROY{print "Foo"} do{1;my $x=bless{}}; p +rint "Bar"' f <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 3 -e:1) v:{ ->3 - <1> null vK*/1 ->b a <@> leave vKP ->b 3 <0> enter v ->4 - <;> ex-nextstate(main 4 -e:1) v ->- - <0> ex-const v ->4 4 <;> nextstate(main 4 -e:1) v ->5 9 <2> sassign vKS/2 ->a 7 <@> bless sK/1 ->8 - <0> ex-pushmark s ->5 6 <@> anonhash sK* ->7 5 <0> pushmark s ->6 8 <0> padsv[$x:4,5] sRM*/LVINTRO ->9 b <;> nextstate(main 6 -e:1) v:{ ->c e <@> print vK ->f c <0> pushmark s ->d d <$> const(PV "Bar") s ->e $ perl -MO=Concise -e 'sub DESTROY{print "Foo"} do{ my $x=bless{}}; p +rint "Bar"' c <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 3 -e:1) v:{ ->3 - <1> null vK*/1 ->8 - <@> scope vK ->- - <;> ex-nextstate(main 4 -e:1) v ->- 7 <2> sassign vKS/2 ->8 5 <@> bless sK/1 ->6 - <0> ex-pushmark s ->3 4 <@> anonhash sK* ->5 3 <0> pushmark s ->4 6 <0> padsv[$x:4,5] sRM*/LVINTRO ->7 8 <;> nextstate(main 6 -e:1) v:{ ->9 b <@> print vK ->c 9 <0> pushmark s ->a a <$> const(PV "Bar") s ->b
    The fact that it works properly when the do contains more than one statement means there isn't a real problem though

    It's still pretty inconsistent behavior IMO. Bug #133720 reported.

    Update: Minor edits to wording.

      If you use -MO=Concise,-exec and put the two programs side by side, one can see the scope (enter+leave) is literally missing.

      do{1;my $x=bless{}}; print "Bar" do{my $x=bless{}}; print "Bar" ================================= ================================= 1 <0> enter 1 <0> enter 2 <;> nextstate(main 3 -e:1) v:{ 2 <;> nextstate(main 3 -e:1) v:{ 3 <0> enter v 4 <;> nextstate(main 4 -e:1) v 5 <0> pushmark s 3 <0> pushmark s 6 <@> anonhash sK* 4 <@> anonhash sK* 7 <@> bless sK/1 5 <@> bless sK/1 8 <0> padsv[$x:4,5] sRM*/LVINTRO 6 <0> padsv[$x:4,5] sRM*/LVINTRO 9 <2> sassign vKS/2 7 <2> sassign vKS/2 a <@> leave vKP b <;> nextstate(main 6 -e:1) v:{ 8 <;> nextstate(main 6 -e:1) v:{ c <0> pushmark s 9 <0> pushmark s d <$> const[PV "Bar"] s a <$> const[PV "Bar"] s e <@> print vK b <@> print vK f <@> leave[1 ref] vKP/REFC c <@> leave[1 ref] vKP/REFC

        It's harder to tell in haukex's version though (without the -exec option) because the shorter version as an extra:  <@> scope vK ->- so it's kind of hard to say that the scope is obviously missing :P. I'm guessing that this is the local scope, that makes local work as intended, but the scope that is *enter*ed and *leave*d (yes I very English, thank you) in the longer version is the lifetime of the scalar.

      The thing is, do always has a return value, if you put ; 1 after the assignment that value is just always 1. Also, since the defect also disappears when you put 1; in front of the assignment, that's why I concluded that it was not about what do returns but rather how many statements are included.

      I also looked at the output of B::Concise, but immediatly concluded that I didn't understand much about it, so I didn't want to draw conclusions on something I had so little grasp on :P

      As for the bug, I guess you're right, I said that the bug shouldn't happen, because there's no need for a lexical in a single statement block, but you don't have to look very far to find one occurence of the issue ... since we're discussing it :P

        -MO=Concise basics:

        • The name of the opcode is followed by flags that are mostly opcode-specific. The exceptions are leading "v"oid, "s"calar and "l"ist, which indicate the context of the opcode.
        • The letters/numbers in the first column are labels generated by B::Concise.
        • A label of "-" denotes an unreachable opcode.
        • A name starting with "ex-" denotes an unreachable opcode.
        • -> is followed by the label of the next opcode in the program.
        • The -exec option (-MO=Concise,-exec) shows the opcodes in the order they are executed, leaving out removed opcodes.
        I concluded that it was not about what do returns but rather how many statements are included

        Yes, your example definitely shed more light on the issue and made it clear my guess was wrong and it's not about the return value, I didn't mean to imply otherwise :-)

        I also looked at the output of B::Concise, but immediatly concluded that I didn't understand much about it, so I didn't want to draw conclusions on something I had so little grasp on :P

        Maybe you should try B::Terse first? ;)





        I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction