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

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.

Replies are listed 'Best First'.
Re^5: File::Temp survival and scope created by "do"
by ikegami (Patriarch) on Dec 10, 2018 at 21:54 UTC

    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.

        because the shorter version as an extra: <@> scope vK ->-

        The - at the start of the line means it's not reachable, though, which is why it doesn't show when using -exec.

        Update: Clarified. It previously said "The leading - ...".

Re^5: File::Temp survival and scope created by "do"
by Eily (Monsignor) on Dec 10, 2018 at 23:22 UTC

    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