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

Can anyone offer an explanation for the value of the second ref below?

c:\test>p1 [0] Perl> $#a=10;; [0] Perl> print \$_ for @a;; SCALAR(0x18eec8c) SCALAR(0x225138) ## Que!??? SCALAR(0x18eec98) SCALAR(0x18eeca4) SCALAR(0x18eecb0) SCALAR(0x18eecbc) SCALAR(0x18eecc8) SCALAR(0x18eecd4) SCALAR(0x18eece0) SCALAR(0x18eecec) SCALAR(0x18eecf8)

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re: Internals question.
by jdporter (Paladin) on Jul 23, 2007 at 12:13 UTC

    When I tried that, I got the oddball in the 8th position, not the second. Expanding it to 20 or 30, it just seems that the array memory is being recycled, probably at least twice, before you get it.

    A word spoken in Mind will reach its own level, in the objective world, by its own weight

      Yes. I think you are right. I also get different results depending upon what has gone on before, but always the same results if the same things have previously happened. So, no matter how many times I run this:

      c:\test>perl -wle"$#a = 10; print \$_ for @a" SCALAR(0x225138) SCALAR(0x225120) SCALAR(0x225144) SCALAR(0x225168) SCALAR(0x1824378) SCALAR(0x224f4c) SCALAR(0x2250f0) SCALAR(0x18243cc) SCALAR(0x18243d8) SCALAR(0x18243e4) SCALAR(0x18243f0)

      I always get those same addresses. The thing I fond confusing is teh way the low and high areans get mixed up.

      For example. When I run these two, notice how the first 7 addresses are the same in both, but then the last 3 vary.

      c:\test>perl -wle"@b = 1.. 10; $#a = 10; print \$_ for @a" Name "main::b" used only once: possible typo at -e line 1. SCALAR(0x225138) SCALAR(0x225120) SCALAR(0x225144) SCALAR(0x225168) SCALAR(0x18243b0) SCALAR(0x1824428) SCALAR(0x1824434) SCALAR(0x1824440 +) SCALAR(0x182beac) SCALAR(0x182beb8) SCALAR(0x182bec4) c:\test>perl -wle"@b = 1.. 100; $#a = 10; print \$_ for @a" Name "main::b" used only once: possible typo at -e line 1. SCALAR(0x225138) SCALAR(0x225120) SCALAR(0x225144) SCALAR(0x225168) SCALAR(0x18243b0) SCALAR(0x1824428) SCALAR(0x1824434) SCALAR(0x1824440 +) SCALAR(0x182bd80) SCALAR(0x182bd8c) SCALAR(0x182bd98)

      And if you go on to:

      c:\test>perl -wle"@b = 1.. 1000; $#a = 10; print \$_ for @a" Name "main::b" used only once: possible typo at -e line 1. SCALAR(0x225138) SCALAR(0x225120) SCALAR(0x225144) SCALAR(0x225168) SCALAR(0x18243b0) SCALAR(0x1824428) SCALAR(0x1824434) SCALAR(0x1824440 +) SCALAR(0x2267c8) SCALAR(0x2267d4) SCALAR(0x2267e0)

      It suddenly starts reusing earlier addresses.

      It came up because I was trying to code something that would rely upon the relative address of the items in an array being in ascending order--but that's a guarentee that Perl simply cannot make.

      What I really need access to is the (C) array of pointers pointed at by the ARRAY field of the XPVAV, but I would have to drop into XS to get that. Still that might be the only way to do what I am trying to do.

      That said, inspiration hit me whilst typing this and I stuck the code is a begin block:

      c:\test>perl -wle"BEGIN{ $#a = 10; print \$_ for @a }" SCALAR(0x182c120) SCALAR(0x182c114) SCALAR(0x182c12c) SCALAR(0x182c138 +) SCALAR(0x182c144) SCALAR(0x182c150) SCALAR(0x182c15c) SCALAR(0x182c168 +) SCALAR(0x182c174) SCALAR(0x182c180) SCALAR(0x182c18c)

      And that seems to produce the effect I am after regardles of what else goes on, provided I ensure that my BEGIN block is run first. Or maybe I should just bite the bullet and code it in Inline::C.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        You can use some perverted B for this. Maybe. This takes an AV, casts it to PV, makes it a real scalar, then fetches the value of the svu_pv pointer which I guess is the same as the svu_array pointer.

        my $addr = pack 'p', bless( svref_2object( \ @ary ), 'B::PV' )->object_2svref;

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        That said, inspiration hit me whilst typing this and I stuck the code is a begin block

        ...and something else may hit you six months from now when the underlying implementation changes for any number of reasons.
        if you want C code, best to code in C.

      Hmm, I didn't get anything weird during at least 10000 iterations:

      # all like SCALAR(0x81nnnnn) $ perl -le'$#a=10000;print \$_ for @a' |fgrep -v x81 $

      But I'm on Ubuntu, not Windows, so maybe it's different.

Re: Internals question.
by shmem (Chancellor) on Jul 23, 2007 at 15:28 UTC
    *shrug* - taking a reference of an alias of an undefined array value, perl can use whatever memory slot it damn well pleases... since you are not saving those references, the slots can be reused. I'd be alarmed if recycling was not the case, which would let me suspect a memory leak.

    update: and perl will just gladly accept memory areas as the underlying OS deals them out. If you have a weird OS (do you? :-), the order may appear weird, but that's not perl's fault. Even on the C level there's no guarantee that malloc()ed memory chunks will be aligned in any order.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      taking a reference of an alias of an undefined array value, ...

      The fact that they are aliases, nor that the array elements are undefined, seems to have no bearing upon the 'problem' at all:

      c:\test>perl -wle"$#a = 10; print \$_ for @a" SCALAR(0x225138) SCALAR(0x225120) SCALAR(0x225144) SCALAR(0x225168) SCALAR(0x1824378) SCALAR(0x224f4c) SCALAR(0x2250f0) SCALAR(0x18243cc) SCALAR(0x18243d8) SCALAR(0x18243e4) SCALAR(0x18243f0) c:\test>perl -wle"@a = 0..10; print \$_, qq[ '$_'] for @a" SCALAR(0x182bd8c) '0' SCALAR(0x182bd98) '1' SCALAR(0x182bda4) '2' SCALAR(0x182bdb0) '3' SCALAR(0x182bdbc) '4' SCALAR(0x182bdc8) '5' SCALAR(0x182bdd4) '6' SCALAR(0x224f4c) '7' SCALAR(0x2250f0) '8' SCALAR(0x182beb8) '9' SCALAR(0x182bec4) '10' c:\test>perl -wle"@a = 0..10; print \$a[ $_ ], qq[ '$a[ $_ ]'] for @a" SCALAR(0x182bdfc) '0' SCALAR(0x182be08) '1' SCALAR(0x182be14) '2' SCALAR(0x182be20) '3' SCALAR(0x182be2c) '4' SCALAR(0x182be38) '5' SCALAR(0x182be44) '6' SCALAR(0x224f5c) '7' SCALAR(0x225100) '8' SCALAR(0x182bf28) '9' SCALAR(0x182bf34) '10'

      And indeed, if I try it in a begin block before anyhting has had a chance to be freed, I get exactly what I was expecting, inspite of the aliases to undefined values:

      c:\test>perl -wle"BEGIN{ $#a = 10; print \$_ for @a }" SCALAR(0x182c120) SCALAR(0x182c114) SCALAR(0x182c12c) SCALAR(0x182c138) SCALAR(0x182c144) SCALAR(0x182c150) SCALAR(0x182c15c) SCALAR(0x182c168) SCALAR(0x182c174) SCALAR(0x182c180) SCALAR(0x182c18c)

      Which pretty much confirms jdporter's view that this is just memory reuse, with the ordering falling out of whatever 'freespace chain mechanism' is used.

      But your pointis well taken. Perl doesn't and shouldn't make any guarentees about the relative ordering of the addresses assigned to consecutive SVs in an array. And my hope that I could force Perl to assign consecutive addresses by pre-allocating a large array early in my program was simply naive.

      I had hoped that by allocating 'big and early' I could force Perl to go to the OS for more space and so get consecutive addresses--which it does to a degree, in as much as, the xvpav has to be allocated as a contiguous chunk of ram. But the SVs it points to, do not. Combine that with the fact that perl manages memory using multiple different sized pools, and it stands to reason that when it comes to allocating those SVs, any old, freed SVs available will get reused.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        taking a reference of an alias of an undefined array value, ...
        The fact that they are aliases, nor that the array elements are undefined, seems to have no bearing upon the 'problem' at all:

        Of course; it's just memory reuse, but I just listed all the facts... ,-)

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Internals question.
by FunkyMonk (Bishop) on Jul 23, 2007 at 14:52 UTC
    And on Linux (Debian/Testing), they're all Wierd™...

    zippy:~/scripts$ perl -v This is perl, v5.8.8 built for x86_64-linux-gnu-thread-multi zippy:~/scripts$ ./pm.pl SCALAR(0x621da0) SCALAR(0x504f50) SCALAR(0x504160) SCALAR(0x5f9c30) SCALAR(0x5f98d0) SCALAR(0x5ef550) SCALAR(0x5ce6b0) SCALAR(0x527ea0) SCALAR(0x559940) SCALAR(0x55a640) SCALAR(0x5ce8d0)