Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Modification of non-creatable array value attempted

by pg (Canon)
on Nov 15, 2005 at 04:57 UTC ( #508481=perlmeditation: print w/ replies, xml ) Need Help??

One of my program went dead after I copied it from one directory to another, I traced the problem, and it came up related to the use of -1 as the index for an empty array. (The program does a glob that creates a non-empty array in the orginal home directory, but not the new place, and the array is then passed to a function call.)

I am sort of fine with the error message, in a way, one can argue that it does not make sense to access the last element of an empty collection. (However it seems to me, undef makes more sense, agrees with the rest of Perl better, and allows more flexibility.)

But I don't like the inconsistency it carries. If you try this code:

my @a = (); print $a[-1]; foo($a[-1]); sub foo { }

It prints:

Use of uninitialized value in print at a.pl line 2. Modification of non-creatable array value attempted, subscript -1 at a +.pl line 3 .

Two issues:

  • It does make sense to me to consider $a[-1] as undef, as what happened to line 2. But it looks like this perception is not followed all the way;
  • Both foo and print are functions, regardless how different they might be underneath, I would expect them to take $a[-1] in the same way.

Comment on Modification of non-creatable array value attempted
Select or Download Code
Re: Modification of non-creatable array value attempted
by Aristotle (Chancellor) on Nov 15, 2005 at 05:43 UTC

    I suspect it’s because putting things into @_ requires making an alias to them, and you can do them for something that actually exists. print obviously works differently, being a builtin.

    $ perl -w
    my @a = ();
    print $a[-1];
    foo("$a[-1]");
    sub foo { }
    ^D
    Use of uninitialized value in print at - line 2.
    Use of uninitialized value in string at - line 3.
    

    I have no idea what should be done about this and how.

    Makeshifts last the longest.

Re: Modification of non-creatable array value attempted
by sauoq (Abbot) on Nov 15, 2005 at 09:51 UTC
    It does make sense to me to consider $a[-1] as undef, as what happened to line 2.

    The problem is, as Aristotle says, passing it to a function means it must be aliased. Aliasing an array element means taking a reference to it. Referencing a non-existent array element means autovivifying it. That's where the "modification" is being attempted. For a minimal example consider:

    perl -e'\$a[0]' perl -e'\$a[-1]'

    Unlike taking a reference to a non-existent array element, taking the value of a non-existent array element does not result in autovivification. To see the difference:

    perl -le '$a[0]; print scalar @a' perl -le '\$a[0]; print scalar @a'
    A non-existent array element is just always an undefined value. I think that's intuitive and as it should be.

    I wonder how (or if) it would make sense to change the behavior of negative array elements during autovivification. At first, it seems the only way to even consider doing it differently might be to special case -1 to mean 0 if the array is empty. But, that's not very useful. It would be like a one-off push(), and, you can be sure that there would be no end to people asking why $a[-1] = 42 for (1 .. 10); didn't work like they expected. That's probably reason enough not to do it. And, it illustrates the real issue... if you special case -1, what about -2? And so on? I guess it could be handled sensibly (for some probably senseless definition of "sensible") if any index less than the negative of the number of elements in @array were treated as $array[$#array + 1]. But still, I don't see much use in it. And it would lead to code like $a[-$_] = 42 for (1 .. 10); which I'm quite sure I don't ever want to see.

    As for the difference between print() and my own functions, I can definitely live with that. It seems that print probably does what I mean in that case. But, to get my own function to behave the same way, Perl would have to provide a way for us to really pass-by-value (rather than just emulating it after the fact through an explicit copy.) And who needs it? In the rare cases where you want to do something like this you could take another approach instead. Any of several other approaches depending on the behavior you needed. For some examples:

    foo( [$a[-1]]->[0] ); do { foo(my $t = $a[-1]) }; foo( defined $a[-1] ? $a[-1] : undef ); foo( "$a[-1]" );
    All of which are ugly and might benefit from a short comment mentioning why it's being done this way. But, again, infrequent constructs like this aren't such a big deal and seem a worthwhile trade-off to the alternatives.

    † PHP behaves like this when no index is given. I.e. $a[] = 42; in PHP is equivalent to push(@a, 42) in Perl. I've actually found it to be a useful shorthand and wouldn't mind it's addition to Perl. At the very least, it would give us an excuse to replay lots of rounds golf.

    -sauoq
    "My two cents aren't worth a dime.";
    

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (8)
As of 2014-12-26 20:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (175 votes), past polls