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

Hi everyone
I found a run error in my code and after a very long time,
I've determined which code line is the 1 responsible for adding an element to my array.
The weird thing is that this line only "looks" at the element, not setting it !
Basically it looks like it is being created because it was "looked" at (very "Heisenberg's uncertainty principle" like).
Hereis my code:
if($cond->{Par} =~ /^K(\d+)/) { my $qqq = scalar(@{$this->{N}}); $testedNVal = $this->{N}[$1]{Val}; # freak line unless($qqq == scalar(@{$this->{N}})) {print 'how is this possible ?';<>;} }
By substituting for $testedNVal = 0 + $this->{N}[$1]{Val};, I could determine the print only occurs when $this->{N}[$1]{Val} is undef (by 'num + undef' warning).
(The new element is a ref, referring an empty hash)
I figured maybe by setting ("=") it directly to a var, I create a reference to something and force it to exist, but if that's correct than the "= 0 +" shouldn't have done the same thing (but it did).

Can someone please explain whats going on, and how can I solve it ?
(if I even ask if it's exists/defined I'll create it by access so.. ?)

Thoughts ?
Thx

Replies are listed 'Best First'.
Re: Can an element be created because it was accessed ? ( || {} )
by tye (Sage) on Dec 29, 2011 at 09:07 UTC

    You can use Data::Diver to avoid this. But I'd go a much simpler route for this case. Simply change:

    $testedNVal = $this->{N}[$1]{Val}; # to $testedNVal = ( $this->{N}[$1] || {} )->{Val};

    [ I personally wouldn't be quick to use autovivification.pm in anything particularly important. Not since I looked over the huge volume of XS code that it contains and how it overrides so dang many bits of Perl's internals. It seems it had a bug where it caused Perl to hang when it tried to compile code like "for(;;){ ... }". I don't see where that even has anything to do with autovivification, ;). Yes, it sticks its fingers way too deep into guts. You'll very likely have no problems with it when you start using it (it seems well written and maintained). But it has the strong smell of ETOOMUCHMAGIC to me and I don't look forward to those "that is really weird" bugs that don't even hint at where the source of the problem is and you spend way too many hours mystified and frustrated and are never quite sure for how long the bug went away this time. ]

    - tye        

Re: Can an element be created because it was accessed ?
by NetWallah (Canon) on Dec 29, 2011 at 01:37 UTC
    You are 'auto-vivifying' the array element, because you are trying to get something beyond it.

    You can fix this by doing

    $testedNVal = exists ( $this->{N}[$1]) ? $this->{N}[$1]{Val} : undef +;

                "Battle not with trolls, lest ye become a troll; and if you gaze into the Internet, the Internet gazes also into you."
            -Friedrich Nietzsche: A Dynamic Translation

      exists( $a[$i] ) doesn't return whether an element exists in an array or not as its name implies, and it's deprecated for that very reason.

      Use $i < @a instead.

      if ( $1 < @{ $this->{N} }) { my $testedNVal = $this->{N}[$1]{Val}; ... }
        That wont work if the array is intentionally sparse.

        Depending on how the O.P enters data into the array, "defined" may be a reasonable choice.

                    "Battle not with trolls, lest ye become a troll; and if you gaze into the Internet, the Internet gazes also into you."
                -Friedrich Nietzsche: A Dynamic Translation

Re: Can an element be created because it was accessed ?
by ikegami (Patriarch) on Dec 29, 2011 at 02:16 UTC