Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

lexicals are all the same scalar and never go out of scope?

by patcat88 (Deacon)
on Dec 06, 2011 at 08:39 UTC ( [id://941973]=perlquestion: print w/replies, xml ) Need Help??

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

#!/usr/bin/perl -w use strict; use Data::Dumper; use Scalar::Readonly ':all'; my $count = 0; my @savearr = (); eval { sub make { save('begin '.$count++.' end'); } sub save { readonly_on($_[0]); #comment this out push(@savearr, \$_[0]); } for(0..3) { make(); } print(Dumper(\@savearr)); }; if($@) { print("failed in eval with\n\"$@\"\n".Dumper(\@savearr)); }
readonly on
C:\Documents and Settings\Owner\Desktop>perl ro.pl failed in eval with "Modification of a read-only value attempted at ro.pl line 9. " $VAR1 = [ \"begin 0 end" ]; C:\Documents and Settings\Owner\Desktop>
readonly off
C:\Documents and Settings\Owner\Desktop>perl ro.pl $VAR1 = [ \"begin 0 end", \"begin 1 end", \"begin 2 end", \"begin 3 end" ]; C:\Documents and Settings\Owner\Desktop>
This is the Perl equivalent of an XS problem I am having. If I turn on readonly, on the next loop run it dies. But this is a second run, with a new value. Old value when out of scope (but still lives in the @savearr). If I comment out the readonly, and it reaches the end, you will see 4 references, to the same, or is that different scalar? Yet the readonly flag proves that its the same scalar and it stays around AFTER it goes out of scope. But the array proves 4 different scalars. Isn't that a violation of what the my keyword and lexical system does? Whats going on here?

Replies are listed 'Best First'.
Re: lexicals are all the same scalar and never go out of scope?
by dave_the_m (Monsignor) on Dec 06, 2011 at 09:54 UTC
    Your sample code is showing some of the effects of pad temps (SVs_PADTMP flag). The first concat op ("begin". $count++) uses its private pad temporary to generate its result; the second concat just appends to this temp, which is then passed to save(). On subsequent calls, concat reuses the same pad temp, which is why setting it readonly makes your code die.

    However, the \ operator has an explicit check that if the thing it's creating a reference to has the SVs_PADTMP flag set, then it makes a copy. Which is why your Data::Dumper output shows four separate values.

    Dave.

Re: lexicals are all the same scalar and never go out of scope?
by moritz (Cardinal) on Dec 06, 2011 at 09:07 UTC
    If I comment out the readonly, and it reaches the end, you will see 4 references, to the same, or is that different scalar?

    Different scalars, as you can easily see from the output of Data::Dumper.

    Yet the readonly flag proves that its the same scalar

    Huh? You've removed the readonly flag for this run. Otherwise you wouldn't get any non-error output at all.

Re: lexicals are all the same scalar and never go out of scope?
by ikegami (Patriarch) on Dec 06, 2011 at 10:08 UTC

    First, you keep talking about my and lexical vars, but the only two lexical vars are $count and @savearr, but your question has nothing to do with either. I have no idea why you keep mentioning them. Of course, that means your ultimate question makes no sense.

    Second, your references are to different scalars. As you said, how else can they have different values as shown in the dump.

    So on to the interesting bit, what is it you're making read-only, and why does it have that effect.

    Each instance of the concatenation operator has a scalar called "TARG" associated with it. The concatenation operator concatenates its operands into its TARG, and it returns its TARG. This is an optimisation, as it saves the operator from making a new scalar every time it's called. You made that scalar read-only, messing with the concatenation operator's ability to change it the next time it is called.

    So how come you end up with references to different scalars? The dereference operator must know something is special about the scalar*, makes a copy of it, and returns a reference to the copy.

    * — I was hoping to provide more details about this, but I've run out of time. I'm guessing it's based on the presence of the PADTMP flag.

Re: lexicals are all the same scalar and never go out of scope?
by Eliya (Vicar) on Dec 06, 2011 at 09:33 UTC

    Try this:

    use Devel::Peek; ... sub save { Dump $_[0]; push(@savearr, \$_[0]); readonly_on(${$savearr[-1]}); Dump ${$savearr[-1]}; } ... __END__ SV = PV(0x75cbc8) at 0x88d238 # REFCNT = 1 FLAGS = (PADTMP,POK,pPOK) PV = 0x77e340 "begin 0 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cc68) at 0x75ef48 REFCNT = 1 FLAGS = (POK,READONLY,pPOK) PV = 0x77e940 "begin 0 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cbc8) at 0x88d238 # REFCNT = 1 FLAGS = (PADTMP,POK,pPOK) PV = 0x77e340 "begin 1 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cce8) at 0x7836b8 REFCNT = 1 FLAGS = (POK,READONLY,pPOK) PV = 0x78cc60 "begin 1 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cbc8) at 0x88d238 # REFCNT = 1 FLAGS = (PADTMP,POK,pPOK) PV = 0x77e340 "begin 2 end"\0 CUR = 11 LEN = 16 SV = PV(0x75ccf8) at 0x783700 REFCNT = 1 FLAGS = (POK,READONLY,pPOK) PV = 0x87bb70 "begin 2 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cbc8) at 0x88d238 # REFCNT = 1 FLAGS = (PADTMP,POK,pPOK) PV = 0x77e340 "begin 3 end"\0 CUR = 11 LEN = 16 SV = PV(0x75cd08) at 0x783748 REFCNT = 1 FLAGS = (POK,READONLY,pPOK) PV = 0x87bcd0 "begin 3 end"\0 CUR = 11 LEN = 16 $VAR1 = [ \'begin 0 end', \'begin 1 end', \'begin 2 end', \'begin 3 end' ];

    Note that the marked instances are in fact the same scalar.  A new one isn't created before pushing it onto the array.

      By your logic, the following never deallocates the referenced array:

      use Devel::Peek; $x = []; Dump($x, 1); $x = undef; $x = []; Dump($x, 1);
      SV = IV(0x51a420) at 0x51a424 REFCNT = 1 FLAGS = (ROK) RV = 0x61b29c SV = PVAV(0x61c248) at 0x61b29c REFCNT = 1 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = IV(0x51a420) at 0x51a424 REFCNT = 1 FLAGS = (ROK) RV = 0x61b29c SV = PVAV(0x61c248) at 0x61b29c REFCNT = 1 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL)

      But that's just not true. It just got reallocated at the same address. Looking at the address is not meaningful.

      (I'm not saying that it isn't the same scalar. I'm saying you haven't shown that it is the same scalar.)

        By your logic, the following never deallocates the referenced array: ...

        This isn't even remotely what I said.  I said the scalar (i.e. the SV, what you call TARG) is the same, and a copy of it is created when a reference to it is pushed onto the array — nothing more.  That's in essence the same you pointed out in your reply.

      But if it is infact 1 scalar, why did the reference become a reference to a copy? Thats not what references do.

      I'll save everyone the drama and point to the culprit pp.c#l522 in perl.git

      So why does perl make copies instead of real references when you think your making a reference? I dont see this in perldoc anywhere. How do I fix this problem when I need to readonly on and save a reference to the SV in XS? Copy what srefgen does by checking PADTMP? Why doesn't newRV sv.c#l8654 in perl.git do the copy for me just like srefgen does? Shouldn't making a ref in XS be identical to making a ref in Perl? Why doesn't entersub clone PADTMPs into unique mortal SVs if PADTMPs are found on the stack automatically so subs (Perl and XS) don't encounter these "supposed to be scoped but are global scalars"? Or get rid of the copying in srefgen and if you run into read only modification fatal error updating a stack scalar in a sub, thats your fault for not eval probing it or checking its readonly flag using Internals:: and the callers fault (assuming its documented all lexicals are private sub level statics/closures and not autos) for passing a lexical instead of something store permanently in an array/hash? Should I be bringing this up on P5P instead?

        So why does perl make copies instead of real references when you think your making a reference?

        $s = $x . $y;

        Wouldn't it be nice if concat didn't have to allocate a scalar that will just end up being copied into $s and deallocated?

        Well guess what, it doesn't. That instance of the concat operator will always return the same scalar. This saves allocating a scalar and deallocating a scalar.

        But of course, doing that alone would break weird code like following:

        my @b = map { \($prefix.$_) } @a;

        So the deref operator must be complicit and make a copy of the scalar if it comes from concat.

        Why doesn't entersub clone PADTMPs into unique mortal SVs if PADTMPs are found on the stack automatically

        Cause that defies the whole point of avoiding the creation of those scalars.

        Shouldn't making a ref in XS be identical to making a ref in Perl?

        Sure, but it's not Perl's fault your XS code isn't identical to its code.

        Should there be a function for creating references that checks PADTMP? Maybe. Yes, p5p would be appropriate for this.

Log In?
Username:
Password:

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

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

    No recent polls found