Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Ref to a list not being equivalent to a list of refs to each element

by Hue-Bond (Priest)
on Jun 22, 2006 at 15:37 UTC ( #556922=perlquestion: print w/replies, xml ) Need Help??

Hue-Bond has asked for the wisdom of the Perl Monks concerning the following question:

(This is not an XY problem, nor something that will go to production; just a question that arose while I was playing with obfuscated code).

Let's declare a constant:

*a = \"cons"; $a = "something"; print "$a\n"; __END__ Modification of a read-only value attempted at - line 2.

That's expected behaviour. Now, a little twisted:

(undef, *a) = \(undef, "cons"); $a = "something"; print "$a\n"; __END__ something

Surprise! What's that? Isn't it a constant anymore? Isn't that reference to a list, a list of references to each element? Well, let's make an explicit list of references then:

(undef, *a) = (\undef, \"cons"); $a = "something"; print "$a\n"; __END__ Modification of a read-only value attempted at - line 2.

This is expected again. But, why does the second snippet behave different?

--
David Serrano

Replies are listed 'Best First'.
Re: Ref to a list not being equivalent to a list of refs to each element
by broquaint (Abbot) on Jun 22, 2006 at 16:22 UTC
    I believe you're seeing this behavior because
    \("foo");
    creates a reference to a temporary value whereas
    \"foo";
    creates a reference to a constant value. I don't know if that is explicitly documented anywhere, but there you have it.
    HTH

    _________
    broquaint

Re: Ref to a list not being equivalent to a list of refs to each element
by Fletch (Chancellor) on Jun 22, 2006 at 16:21 UTC

    OK, only a shot in the dark after playing with B::Concise and B::Deparse but here goes . . .

    In the first and third cases the reference is to a readonly PV value. This is copied directly into the SV slot of *a and when you try and modify it you get the error.

    In the middle case either a non-readonly copy of the PV is pushed onto the stack, or the make-reference-to-list opcode (refgen I think) makes a non-readonly copy. Whichever case it is, the PV that's stuck in the SV slot of *a is mutable.

Re: Ref to a list not being equivalent to a list of refs to each element
by davido (Cardinal) on Jun 22, 2006 at 16:55 UTC

    That's an interesting quirk you've found.

    This discussion does present the opportunity to discuss the creation of constants. There's always the constant pragma, but it makes interpolation difficult and syntax confusing. There's your typeglob method, but the fact that *variable = \'value'; creates a sort of immutable constant is itself simply a side effect, easily forgotten unless one brushes up on the POD periodically.

    How about the use Readonly; solution?

    use strict; use warnings; use Readonly; Readonly my $VAR => 'value'; #......

    It's clear, it states what it does explicitly, and it interpolates properly. Are there negatives to this approach? The ones I can think of are that not everyone will have Readonly.pm installed (but it's easy), and also, unless Readonly::XS.pm is also installed, the new readonly variables will incur a slight performance hit.


    Dave

Re: Ref to a list not being equivalent to a list of refs to each element
by Errto (Vicar) on Jun 22, 2006 at 18:23 UTC
    A related quirk I ran across earlier, and which I also am not sure is documented (though I may have missed it), is that references to literal strings are read-only, but references to computed strings, including interpolated literals, are not. For example
    my $x = 'foo'; my $y = \"bar$x"; $$x = 'baz';
    does not throw any errors or warnings. Does anyone know why exactly that is?
      This occurs for the same reasons given above as
      \"foo";
      creates a references to a constant value whereas
      \"foo$x";
      is creating a reference to a temporary value.

      If you want to see the evidence then just put Devel::Peek to work (take note of the FLAGS values for the reference):

      use Devel::Peek; my $x = 'foo'; Dump \'foo'; Dump \"bar$x"; __output__ SV = RV(0x183c90c) at 0x225fe4 REFCNT = 1 FLAGS = (PADBUSY,PADTMP,ROK,READONLY) RV = 0x225ffc SV = PV(0x22626c) at 0x225ffc REFCNT = 1 FLAGS = (POK,READONLY,pPOK) PV = 0x1831d04 "foo"\0 CUR = 3 LEN = 4 SV = RV(0x183c92c) at 0x2252ac REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x225150 SV = PV(0x2261a0) at 0x225150 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x1831cac "barfoo"\0 CUR = 6 LEN = 7
      HTH

      _________
      broquaint

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (8)
As of 2020-08-06 09:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which rocket would you take to Mars?










    Results (39 votes). Check out past polls.

    Notices?